Pruebas unitarias en Spring con JUnit
Generar pruebas unitarias de los componentes de nuestras aplicaciones es una tarea que puede llegar a ahorrarnos bastantes dolores de cabeza, a través de estas damos pasos adelante en el aseguramiento de la calidad del software que construimos. La evolución de los frameworks de pruebas modernos nos ha proporcionado la oportunidad de poder generar componentes de pruebas basados en anotaciones como en el caso de JUnit.
Realizar estas pruebas en las aplicaciones que construimos con Spring framework implica como mínimo levantar en contenedor de injección de dependencias para la correcta inicialización de los beans a utilizar. Una de las tantas extensiones que han surgido como parte de Spring Framework es Spring TestContext Framework el cual representa una capa consistente para la generación de pruebas unitarias sobre aplicaciones Spring con diversos frameworks de pruebas como JUnit (3 y 4), TestNG, etc. A continuación veremos cómo hacer uso del Spring TestContext Framework.
Vamos replantear el ejemplo de JUnit, especificando que ahora ProductDao será un Spring bean por lo tanto tendríamos la siguiente configuración en el archivo de spring que ahora denominaremos "testing-context.xml".
<bean id="productDao" class="org.yaxche.blog.springtestjunit.ProductDao">
<constructor-arg ref="datasource"></constructor-arg>
</bean>
<bean id="datasource" class="org.yaxche.blog.springtestjunit.DataSource">
...
</bean>
La clase ProductDao lucirá ahora de la siguiente manera.
package org.yaxche.blog.springtestjunit;
...
import javax.annotation.Resource;
...
public class ProductDao {
@Resource(name = "datasource")
private DataSource datasource;
public ProductDao(DataSource datasource) {
this.datasource = datasource;
}
public List<Product> findByCategory(Category category) {
...
}
}
Se trata de una configuración común y normal en Spring, una clase ProductDao que tiene una dependencia hacia otra clase Datasource y dicha dependencia es especificada en el archivo de configuración de contexto de Spring. Por otro lado la clase de prueba unitaria quedará de la siguiente manera.
package org.yaxche.blog.springtestjunit;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:testing-context.xml"})
public class ProductDaoTest {
@Resource(name = "productDao")
private ProductDao productDao;
private Category category;
@AfterClass
public static void tearDownClass() throws Exception {
datasource.close();
...
}
@Before
public void setUp() {
category = new Category("music");
}
@After
public void tearDown() {
category = null;
...
}
@Test
public void testFindByCategory() {
List<Product> prodList = (List<Product>) productDao.findByCategory(category);
assertNotNull(prodList);
}
}
Veamos ahora los detalles que marcan la diferencia
@RunWith
Esta anotación fue una de las caractrísticas más destacadas introducidas a JUnit a partir de su versión 4. Y sirve para que la ejecución de la clase de prueba unitaria la efectúe la clase especificada como parámetro value y no la clase Runner por defecto de JUnit, cabe destacar que dicha clase debe heredar de org.junit.runner.Runner. En el ejemplo se está especificando org.springframework.test.context.junit4.SpringJUnit4ClassRunner la cual levantará el contexto de spring, resolviendo las dependencias que sean requeridas por la clase de prueba unitaria.
@ContextConfiguration
Esta anotación foirma parte del Spring TestContext Framework y sirve para indicar la configuración del contexto de spring. En el parámetro locations recibe un arreglo de Strings con las ubicaciones de los archivos de configuración.
Todo esto es puesto en uso cuando inyectamos a la prueba la clase ProductDao, la cual dada la configuración anterior ya tiene sus dependencias resueltas.
