2010-06-09 13 views
12

Spring Test reduce de forma útil cualquier cambio realizado en la base de datos dentro de un método de prueba. Esto significa que no es necesario tomarse el tiempo para eliminar/volver a cargar los datos de prueba antes de cada método de prueba.Cómo cargar los datos de prueba de DBUnit una vez por caso con Spring Test

Pero si utiliza la anotación @BeforeClass Junit, eso fuerza al cargador de datos a ser estático. Una pregunta que se explora aquí: Why must jUnit's fixtureSetup be static?

Si el método de inicialización de datos es estático, también lo deben hacer los métodos de conexión de datos y la fuente de datos ... y así sucesivamente ... obligando a todo a ser estático ... que ganó ' t trabajo. En ese momento, pregunto: ¿de qué sirve la capacidad de Spring Test de deshacer cambios cuando tiene que eliminar/volver a cargar los datos de prueba de todas las pruebas?!?!

Respuesta

14

Un enfoque que funciona es crear una clase de "inicializador de datos", agregarla a un contexto de aplicación Spring de prueba que también tenga su fuente de datos y conectar este contexto de aplicación en sus pruebas. Esto se basa en el hecho de que Spring almacena el contexto de la aplicación entre invocaciones de prueba.

Por ejemplo, una superclase de prueba:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations={"classpath:test-application-context.xml"}) 
@Transactional 
public abstract class DataLoadingTest { 
    @Autowired 
    protected DatabaseInitialiser databaseInitialiser; 
} 

Con test-application-context.xml:

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
    <bean id="dataSource" .../> 

    <bean class="DatabaseInitialiser"> 
     <property name="dataSource" ref="dataSource"/> 
    </bean> 
</beans> 

Y

public class DatabaseInitialiser extends JdbcDaoSupport { 
    @PostConstruct 
    public void load() { 
     // Initialise your database here: create schema, use DBUnit to load data, etc. 
    } 
} 

En este ejemplo:

  • todas las pruebas que dependen de la base de datos extienden DataLoadingTest;
  • Spring inicializa el contexto de la aplicación en la primera invocación de prueba;
  • esto llama a DatabaseInitialiser.load(), a través de la anotación @PostConstruct;
  • Spring mantiene el contexto de la aplicación en un caché;
  • invocaciones de prueba adicionales cableadas en el DatabaseInitialiser desde el contexto de la aplicación, que ya está en caché;
  • Las pruebas son transaccionales y se retrotraen al final del conjunto de datos inicial.

Asimismo, DatabaseInitialiser puede tener un método anotado @PostDestroy para realizar cualquier rollback necesario, al final de toda la ejecución de prueba.

+0

Esto es, de hecho, exactamente cómo resolví el problema, me olvidé de volver a poner mi código/respuesta en SO. Gracias por tomarse el tiempo para hacer esto para el próximo tipo. – HDave

+0

Suena bien, pero en la práctica el '@PostConstruct' de la otra clase se ejecuta antes que el DatabaseInitialiser, por lo que no sirve de nada. Gracias por cualquier ayuda. –

+0

@ united-expression: ¿puedes ampliar eso? ¿A qué otra clase te refieres? En el ejemplo que tengo, Spring inicializa el inicializador de la base de datos antes de la clase de prueba, que funciona en el Cass delineado en la pregunta. – Kkkev

1

Spring Test y DbUnit son dos marcos excelentes. Pero no tiene sentido combinarlos. Dado que Spring Test ejecuta una reversión en la conexión, se limpia después, mientras que DbUnit limpia e inserta datos de prueba en el método @Before.

Use Spring si no depende de ningún dato dinámico y dbUnit en caso contrario.

+0

Encuentro conveniente la capacidad de DBUnit de cargar una tabla de base de datos desde XML. ¿Spring Test tiene una capacidad como esta? – HDave

+1

Sí, creo que Mats está equivocado aquí. Cargar datos de prueba de un archivo XML es un buen beneficio para las pruebas de DB con Spring. – IcedDante

1

Utilizamos DBUnit conjuntamente con Spring Test exhaustivamente. Pero no utilizamos la funcionalidad DBUnit para eliminar datos al final de la prueba.

Colocamos un conjunto de insertos DBUnit para nuestros datos de prueba en el método @Before para inicializar la prueba. Luego, cuando se completa la prueba, dejamos que la funcionalidad de retrotracción de la primavera devuelva a la base de datos a su estado original.

El mayor problema que tenemos con esto es que los datos DBUnit deben cargarse antes de cada prueba, lo que puede ser un gran golpe de rendimiento. La mayoría de nuestras pruebas con DBUnit son de solo lectura, probando el comportamiento de la aplicación en función de un comportamiento predefinido. Entonces, tenemos la costumbre de crear pruebas maestras que luego ejecutan todas las pruebas de grano fino en un lote dentro de la misma transacción.

+1

Bueno, eso es una mala práctica. ¿Qué piensas de la solución comprobada? – IcedDante

0

Métodos annotated with @BeforeTransaction ejecutar, como su nombre lo indica, antes de iniciar la transacción de cada prueba. Si en dicho método puede detectar si los datos de prueba están cargados, entonces uno puede cargar los datos cuando sea necesario.

Tenga en cuenta que los datos quedan en su base de datos (en memoria) para todas las pruebas posteriores.

Utilizamos esto para cargar datos "estáticos" que, en un entorno de producción, también se iniciarían en nuestra base de datos al iniciarlo. De esta forma, realmente usamos exactamente el mismo código y los mismos datos para nuestras pruebas, en lugar de confiar en las exportaciones (DbUnit) que podrían quedar obsoletas.

Cuestiones relacionadas