test - spring pruebas unitarias
¿Cómo se restablece el contexto de la aplicación Spring JUnit después de que una clase de prueba lo ensucie? (1)
Estoy utilizando Spring 3.1.1.RELEASE, JUnit 4.8.1 y la base de datos en memoria HSQL 2.7.7. Tengo una clase de prueba anotada como
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-trainingSessionServiceContext.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class TrainingSessionServiceTest
{
El problema es que cuando ejecuto "mvn clean test", parece que todas las clases de prueba se ejecutan después de que la clase anterior falle porque la base de datos en memoria se destruye y no se vuelve a crear. Recibo errores como
org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: CB_ORGANIZATION" type="javax.persistence.PersistenceException">javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: user lacks privilege or object not found: CB_ORGANIZATION
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1360)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:817)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:771)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy46.find(Unknown Source)
at org.mainco.subco.organization.repo.OrganizationDaoImpl.findById(OrganizationDaoImpl.java:77)
at org.mainco.subco.pd.repo.LinkDaoTest.createDummyLink(LinkDaoTest.java:686)
at org.mainco.subco.pd.repo.LinkDaoTest.testSaveLink(LinkDaoTest.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
Aquí es cómo configuro la clase de prueba (ejecutar después de la clase anterior) que da las excepciones ...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class LinkDaoTest extends AbstractTransactionalJUnit4SpringContextTests
{
¿Hay alguna manera de restaurar el contexto de mi aplicación a su estado original antes de ejecutar cada clase de prueba? No quiero hacer que la clase "TrainingSessionServiceTest" extienda AbstractTransactionalJUnit4SpringContextTests. Aquí está la parte relevante de mi contexto de aplicación:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:pd" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="persistenceXmlLocation" value="classpath:META-INF/test-persistence.xml"/>
<property name="persistenceUnitName" value="testingDatabase"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven />
<jdbc:embedded-database id="embedded" type="HSQL"/>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:db-test-data.sql"/>
</jdbc:initialize-database>
Use @DirtiesContext para forzar un reinicio. Por ejemplo, tengo:
@ContextConfiguration(classes={BlahTestConfig.class})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class SomeTest {
@Autowired XXXX xx;
@Autowired YYYY yy;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(YYYY.newYY()).thenReturn(zz);
}
@Test
public void testSomeTest() {
XX.changeSomething("StringTest");
XX.doSomething();
check_for_effects();
}
@Test
public void testSomeOtherTest() {
XX.changeSomething("SomeotherString");
XX.doSomething();
check_for_effects();
}
De los documentos de primavera
DirtiesContext
Indica que el Spring ApplicationContext subyacente se ha ensuciado (modificado) de la siguiente manera durante la ejecución de una prueba y debe cerrarse, independientemente de si se pasó la prueba:
Después de la clase de prueba actual, cuando se declara en una clase con el modo de clase establecido en AFTER_CLASS, que es el modo de clase predeterminado.
Después de cada método de prueba en la clase de prueba actual, cuando se declara en una clase con el modo de clase establecido en AFTER_EACH_TEST_METHOD.
Después de la prueba actual, cuando se declara en un método.
Use esta anotación si una prueba ha modificado el contexto (por ejemplo, reemplazando una definición de bean). Las pruebas posteriores se suministran en un nuevo contexto. [Nota] Limitaciones de @DirtiesContext con JUnit 3.8
> En un entorno JUnit 3.8 @DirtiesContext solo se admite en métodos y, por lo tanto, no en el nivel de clase.
Puede usar @DirtiesContext como una anotación de nivel de clase y nivel de método dentro de la misma clase. En tales escenarios, ApplicationContext se marca como sucio después de cualquier método anotado así como también después de toda la clase. Si ClassMode se establece en AFTER_EACH_TEST_METHOD, el contexto se marca sucio después de cada método de prueba en la clase.
@DirtiesContext
public class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
@DirtiesContext
@Test
public void testProcessWhichDirtiesAppCtx() {
// some logic that results in the Spring container being dirtied
}
Cuando un contexto de aplicación se marca como sucio, se elimina de la caché del marco de prueba y se cierra; por lo tanto, el contenedor de Spring subyacente se reconstruye para cualquier prueba posterior que requiera un contexto con el mismo conjunto de ubicaciones de recursos.