====== JUnit4 ======
//
Desde que empecé a estudiar esto del java, hace unos dos años, han cambiado muchas cosas, y se nota por el perfil de este artículo que voy a escribir. Mientras que antes hablaba de cómo se manejaba un fichero, o cómo se conectaba a una base de datos usando jdbc, ahora vamos a ir a un tema muy específico: integrar JUnit4 con Spring 3.0.2 y con Eclipse Helios.
//
===== Introducción =====
Los que hayais intentado integrar JUnit 4 con Spring 3.0.2 tendreis dos opiniones del asunto: 1) es tremendamente fácil, no tiene sentido este artículo y 2) ¿Porqué demonios hay tanto material en internet --incluso en la propia web de Junit y de Spring y nada me funciona??? ¿qué demonios estoy haciendo mal???
Y la tercera pregunta ¿Porqué el testSuite que me he creado para Junit no me funciona???
Vamos por partes, queridos amigos.
===== El ejemplo =====
Comenzaremos por configurar Eclipse Helios para que acepte JUnit 4 y nada más:
* Haremos click con el botón derecho sobre el icono del proyecto y seleccionaremos "propiedades"
* En la opcion "Java Build Path" seleccionaremos "Libraries"
* click en "add library": seleccionar JUnit y luego JUnit4
Luego, dentro de la carpeta de los fuentes --"src" en mi caso--, crearemos un nuevo paquete para alojar las clases de los tests.
**Regla 1: dentro de este paquete tiene que haber una copia del fichero ''applicationContext.xml'' de Spring.** No me pregunteis porqué, pero en mi ejemplo lo va a buscar ahí, y no hay manera de hacerle desistir. ¿A lo mejor es porque dice el manual que lo buscará sólamente en el CLASSPATH?? puede ser....
Usuarios de linux: para mantener una única copia del fichero ''applicationContext.xml'' se puede crear un enlace virtual. Viva Linux!!!
Y ahora creamos nuestro primer test.
===== Primer error: creando el primer test =====
Ingenuo de mí, pensé que si configuraba eclipse para que usara la librería de JUnit4, crearía tests para JUnit4.... ¡Qué ingenuo, madre!!!! Los muchachos de eclipse.org aún no se han dado cuenta y el asistente de eclipse crea **solamente** test para JUnit 3.x.
**Regla 2: los tests hay que escribirlos __A MANO__. Olvidaros de asistentes y otras chorradas. __A MANO__ ¿He dicho ya que los tests hay que escribirlos a mano??? Pues eso, que los escribais a mano.**
Aquí os pongo un test de ejemplo que he escrito __A MANO__ leyendo de aquí y de allí en internet.
package test;
import htmlCleaner.htmlElement;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.Assert.*;
@ContextConfiguration(locations={"applicationContext.xml"})
public class HTMLElementTest extends AbstractJUnit4SpringContextTests
{
// just for using AbstractJUnit4springContextTests
// we have the applicationContext instance variable
// will access to the instance of the Application
// Context
// this instance will be dependency injected by name
@Autowired
private htmlElement element;
@Before
public void heating() throws Exception
{
System.out.println("hello setup method");
}
@After
public void cooling() throws Exception
{
System.out.println("goodbye setup");
}
@Test
public void testATest()
{
System.out.println("hello spring");
element.setIdAndContent( -1, new StringBuilder("hola") );
assertTrue( true );
}
}
Por cierto, agradeceré enormemente que alguien me explique porqué los ejemplos los pone la gente sin los "import". Hala, ahí te las compongas para buscar de dónde han salido las clases!!!
==== Explicando un poco el asunto ====
@ContextConfiguration(locations={"applicationContext.xml"})
El meollo del maridaje JUnit - Spring. ContextConfiguration consigue proveer un contexto de aplicación para el test. Además de que nos va a hacer el Autowiring --o sea, crear automáticamente los //beans// que necesitemos--, es así de majo que nos deja disponible en la propiedad ''applicationContext'' linea directa con el contexto de aplicación, por si nos apetece crear un bean que nos haga falta.
==== Enchufando cosas ====
// this instance will be dependency injected by type
@Autowired
private htmlElement element;
La anotacion ''@Autowired'' permite que una propiedad sea auto-conectada en el momento de la creación del test. Va a identificarla por tipo. En otras palabras, buscará un bean que sea del mismo tipo htmlElement que hemos definido, y va y se lo casca.
**¿Qué pasa si hay dos bean del mismo tipo???** pues que entonces se hace un lío. En ese caso ''[[http://static.springsource.org/spring/docs/3.0.2.RELEASE/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers|@Qualifier]]'' viene al rescate, permitiendonos identificar el bean concreto.
Las anotaciones ''@Before'', ''@After'', ''@Test'' creo que os podeis imaginar lo que hacen.
===== Ejecutando el test =====
Sobre la clase, boton derecho, Run As -> Junit Test y se lanzará el test, mostrando algo así:
31-jul-2010 0:54:00 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [test/applicationContext.xml]
31-jul-2010 0:54:00 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@351e1e67: startup date [Sat Jul 31 00:54:00 CEST 2010]; root of context hierarchy
31-jul-2010 0:54:00 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4ce66f56: defining beans [htmlCleaner,htmlTokenizer,htmlElement,tagTokenizer,tagParser,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor]; root of factory hierarchy
hello setup method
hello spring
goodbye setup
Si os sale una ventana de configuración de ejecución teneis que seleccionar que eclipse ejecute el test como un test de JUnit4. Dato importante.
Otro problema bastante común es que se produce un error "File not found exception": a mí me ocurrió porque no tenía el fichero applicationContext.xml en la misma carpeta que la clase.
===== Segundo error: Creando una Suite que agrupe a todos los test =====
Tampoco se os ocurra crear la suite de tests usando el asistente de eclipse. Aquí hay que picarlo todo a mano. Os paso un ejemplo de los muchos que hay por internet:
package test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({HTMLTokenizerTest.class,
HTMLCleanerTest.class,
HTMLElementTest.class})
public class AllTests
{
}
''HTMLTokenizerTest.class'', ''HTMLCleanerTest.class'' y ''HTMLElementTest.class'' son las clases de test que he creado para este ejemplo.
===== Documentasao =====
* [[http://static.springsource.org/spring/docs/2.5.x/reference/testing.html]]
* [[http://aows.wordpress.com/2009/11/03/inyeccion-dependecias-spring-autowired-qualifier-resource/|Sobre Qualifier]]
* [[http://stackoverflow.com/questions/457276/junit4-test-suites]]
* [[http://kentbeck.github.com/junit/javadoc/latest/]]
* JUnit4, gracias por nada!!!
*