Spring Test

De Dos Ideas.
Saltar a: navegación, buscar

Spring Framework contiene un conjunto de clases pensadas para realizar Prueba Unitaria y Prueba De Integracion, facilitando varias tareas repetitivas. En particular, estas utilidades se integran directamente con JUnit.

Spring Test provee:

  • integración con JUnit
  • acceso al factory de beans directamente desde los test unitarios
  • inyección automática de la clase bajo test en el TestCase
  • rollback automático de transacciones contra bases de datos
  • acceso a la conexión jdbc para realizar querys de comprobación
  • y varias utilidades más.

El uso general de Spring Test implica escribir casos de prueba de JUnit que hereden de clases abstractas de Spring Test.

JUnit 3.x

El soporte para JUnit 3.x está obsoleto a partir de Spring Framework 3.0.

La clase AbstractDependencyInjectionSpringContextTests

La clase AbstractDependencyInjectionSpringContextTests provee a los tests que heredan acceso al factory de spring. Esta es la clase más práctica para usar con Spring, a menos que se quiera manejo de transacciones (ver a continuación).

Al heredar de esta clase se debe sobreescribir el método getConfigLocations(), el cual devuelve los XML de Spring a cargar. Luego, en los tests, es posible utilizar el objeto applicationContext que viene heredado, y del cual podremos obtener los objetos.

public class InvasorBoTest extends AbstractDependencyInjectionSpringContextTests {
    private InvasorBo invasorBo;
    @Override
    protected String[] getConfigLocations() {
        return new String[] { "classpath:application-db.xml",
                              "classpath:application-bo.xml"};
    }
    @Override
    public void onSetUp() {
        invasorBo = (InvasorBo) applicationContext.getBean("business.InvasorBo");
    }
    /** Busca un invasor por su identificador unico */
    public void testBuscar() {
        System.out.println("testBuscar");
        String idInvasor = 100;

        Invasor invasor = invasorBo.buscar(idInvasor);
        assertNotNull(invasor);
        assertEquals(idInvasor, invasor.getId());
    }
}

La clase AbstractTransactionalDataSourceSpringContextTests

La clase AbstractTransactionalDataSourceSpringContextTests provee a los tests que hereden acceso al factory de spring, y rollback automático de las transacciones.

Esta clase es muy útil para testear DAO o cualquier otro objeto que modifique datos en una Base De Datos.

public class InvasorDaoTest extends AbstractTransactionalDataSourceSpringContextTests {

    private InvasorDao invasorDao;

    @Override
    protected String[] getConfigLocations() {
        return new String[] { "classpath:application-db.xml",
                              "classpath:application-hibernate.xml",
                              "classpath:application-dao.xml"};
    }

    @Override
    public void onSetUp() {
        invasorDao = (InvasorDao) applicationContext.getBean("dao.InvasorDao");
    }

    /** Inserta una fila en una tabla */
    public void testGuardar() {
        System.out.println("testGuardar");
        int cantOriginal = countRowsInTable("INVASORES");
        Invasor invasor = new Invasor();
        invasor.setNombre("Zim");
        invasor.setOrden("Invadir la Tierra");

        invasorDao.guardar(invasor);

        int cantInsert = countRowsInTable("INVASORES");
        assertEquals(cantOriginal + 1, cantInsert);
    }
}

Explicación

El método getConfigLocations() devuelve la lista de archivos de configuración. Obviamente, lo recomendable es crear una superclase que sobreescriba dicho método, y todos los tests heredarlos de dicha clase.

El método countRowsInTable() es uno de los métodos heredados utilitarios que tiene la aplicación (cuenta la cantidad de filas de una tabla). A su vez, a través del atributo jdbcTemplate (también heredado) es posible realizar consultas en la misma transacción.

Más aún, es posible forzar el commit de la transacción si así se deseara.

JUnit 4.x

Spring Framework 2.5.x funciona con JUnit 4.4; Spring Framework 3.0 ya trae soporte para JUnit 4.5 y superior.

Si se utiliza JUnit 4.x, la configuración para inyección es mucho más simple, haciendose a través de anotaciones:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {

   "classpath:application-db.xml",
   "classpath:application-bo.xml"

}) public class InvasorBoTest {

    /** La anotacion Autowired inyecta automáticamente el bean de acuerdo a su tipo */
    @Autowired
    private InvasorBo invasorBo;
    /** Busca un invasor por su identificador unico */
    @Test
    public void buscar() {
        System.out.println("testBuscar");
        String idInvasor = 100;

        Invasor invasor = invasorBo.buscar(idInvasor);
        assertNotNull(invasor);
        assertEquals(idInvasor, invasor.getId());
    }

}

La anotación @RunWith(SpringJUnit4ClassRunner.class) hace que Spring levante su factory y prepare la ejecución. De forma alternativa se puede heredar de la clase AbstractJUnit4SpringContextTests; de hacerlo, se tiene acceso al contexto de Spring y otras utilidades.

Transacciones

Es posible manejar las transacciones en los tests, de manera de hacer un rollback automático de las operaciones realizadas. Para esto usamos la anotación @TransactionConfiguration y @Transactional.

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {

   "classpath:application-db.xml",
   "classpath:application-bo.xml"

}) @TransactionConfiguration(transactionManager="transactionManager") @Transactional public class InvasorBoTest {

    /** La anotacion Autowired inyecta automáticamente el bean de acuerdo a su tipo */
    @Autowired
    private InvasorBo invasorBo;
    /** Este test tendrá un rollback automático  */
    @Test
    public void buscar() {
        ...
    }

}

La anotación @TransactionConfiguration indica cuál es el transactionManager que utilizarán los tests y sobre el cual se hará un rollback. La anotación @Transactional hace transaccional a toda la clase de test.

Ver también