web-dev-qa-db-fra.com

Comment réinitialiser le contexte de l'application Spring JUnit après qu'une classe de test l'ait modifié?

J'utilise Spring 3.1.1.RELEASE, JUnit 4.8.1 et la base de données en mémoire HSQL 2.7.7. J'ai une classe de test annotée comme

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-trainingSessionServiceContext.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class TrainingSessionServiceTest  
{

Le problème est que lorsque j'exécute "mvn clean test", il semble que toutes les classes de test s'exécutent après l'échec de la classe ci-dessus car la base de données en mémoire est détruite et non recréée. Je reçois des erreurs comme

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)

Voici comment j'ai configuré la classe de test (exécutée après la classe ci-dessus) qui donne les exceptions…

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class LinkDaoTest extends AbstractTransactionalJUnit4SpringContextTests
{

Existe-t-il un moyen de restaurer mon contexte d'application à son état d'origine avant l'exécution de chaque classe de test? Je ne veux pas que la classe "TrainingSessionServiceTest" étende AbstractTransactionalJUnit4SpringContextTests. Voici la partie pertinente de mon contexte d'application:

<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>  
52
Dave

Utilisez @DirtiesContext pour forcer une réinitialisation. Par exemple, j'ai:

@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 documents de printemps

DirtiesContext

Indique que le Spring ApplicationContext sous-jacent a été sali (modifié) comme suit lors de l'exécution d'un test et doit être fermé, que le test ait réussi ou non:

  • Après la classe de test actuelle, lorsqu'elle est déclarée sur une classe avec le mode de classe défini sur AFTER_CLASS, qui est le mode de classe par défaut.

  • Après chaque méthode de test dans la classe de test actuelle, lorsqu'elle est déclarée sur une classe avec le mode de classe défini sur AFTER_EACH_TEST_METHOD.

  • Après le test en cours, lorsqu'il est déclaré sur une méthode.

Utilisez cette annotation si un test a modifié le contexte (par exemple, en remplaçant une définition de bean). Les tests suivants sont fournis dans un nouveau contexte. [Remarque] Limitations de @DirtiesContext avec JUnit 3.8

> Dans un environnement JUnit 3.8, @DirtiesContext n'est pris en charge que sur les méthodes et donc pas au niveau de la classe.

Vous pouvez utiliser @DirtiesContext comme une annotation au niveau de la classe et au niveau de la méthode dans la même classe. Dans de tels scénarios, ApplicationContext est marqué comme sale après une telle méthode annotée ainsi qu'après la classe entière. Si le ClassMode est défini sur AFTER_EACH_TEST_METHOD, le contexte est marqué comme sale après chaque méthode de test de la classe.

@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
}

Lorsqu'un contexte d'application est marqué comme sale, il est supprimé du cache du framework de test et fermé; ainsi, le conteneur Spring sous-jacent est reconstruit pour tout test ultérieur qui nécessite un contexte avec le même ensemble d'emplacements de ressources.

82
Lmwangi