2013-02-05 9 views
26

Utilizzo Spring 3.1.1.RELEASE, JUnit 4.8.1 e il database in memoria HSQL 2.7.7. Ho una classe di test annotata comeCome si ripristina il contesto dell'applicazione Spring JUnit dopo che una classe di test lo sporca?

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

Il problema è che quando faccio funzionare "mvn prova pulita", sembra che tutte le classi di test eseguiti dopo la classe sopra falliscono perché il database in memoria è distrutto e non ri -creato. Ricevo errori come

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) 

Ecco come ho configurato il classe di test (eseguito dopo che la classe di cui sopra) che dà le eccezioni ...

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

C'è un modo per ristabilire il mio contesto di applicazione alla sua stato originale prima dell'esecuzione di ogni classe di test? Non voglio fare in modo che la classe "TrainingSessionServiceTest" estenda AbstractTransactionalJUnit4SpringContextTests. Ecco la parte rilevante del mio contesto applicativo:

<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> 
+0

Per me l'errore mostrato sopra non sembra correlato al contesto di primavera, ma al database hsqldb non inizializzato correttamente: il metodo di test fa cadere un database o un utente? –

+0

Possibile duplicato di [Ricarica il contesto dell'applicazione Spring dopo ogni test] (http://stackoverflow.com/questions/13288029/reload-spring-application-context-after-every-test) – radistao

risposta

51

Utilizzare @DirtiesContext per forzare un ripristino. Per esempio ho:

@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(); 
    } 

Da spring docs

DirtiesContext

Indica che il sottostante Spring ApplicationContext è stato sporcato (modificato) come segue durante l'esecuzione di un test e deve essere chiuso , indipendentemente dal test superato:

  • Dopo la classe di test corrente, quando dichiarata su una classe con la modalità impostata su AFTER_CLASS, che è la modalità di classe predefinita.

  • Dopo ogni metodo di prova nella classe di test corrente, quando dichiarato su una classe con modalità classe impostata su AFTER_EACH_TEST_METHOD.

  • Dopo il test corrente, quando dichiarato su un metodo.

Utilizzare questa annotazione se un test ha modificato il contesto (ad esempio sostituendo una definizione di bean). I test successivi vengono forniti in un nuovo contesto. [Nota] Limitazioni di @DirtiesContext con JUnit 3.8

> In un JUnit 3.8 ambiente @DirtiesContext è supportato solo su metodi e quindi non a livello di classe.

È possibile utilizzare @DirtiesContext come annotazione a livello di classe e a livello di metodo all'interno della stessa classe. In tali scenari, ApplicationContext viene contrassegnato come dirty dopo qualsiasi metodo annotato così come dopo l'intera classe. Se ClassMode è impostato su AFTER_EACH_TEST_METHOD, il contesto viene contrassegnato come dirty dopo ogni metodo di test nella 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 
} 

Quando un contesto di applicazione è contrassegnato come dirty, viene rimosso dalla cache del framework di test e chiuso; quindi il contenitore Spring sottostante viene ricostruito per qualsiasi test successivo che richiede un contesto con lo stesso insieme di posizioni delle risorse.

+8

Um ... non @ Dave's codice originale ** già ** usa 'DirtiesContext', come mostrato sopra. Non riesco a vedere eventuali modifiche. Cosa mi manca? – Edmund

+1

A seconda del caso d'uso, potrebbe essere necessario aggiungere questa impostazione al plugin mvn surefire: false

+0

ha salvato la mia giornata. Molte grazie! – radistao

Problemi correlati