Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you reset Spring JUnit application context after a test class dirties it?

I'm using Spring 3.1.1.RELEASE, JUnit 4.8.1 and the HSQL 2.7.7 in-memory database. I have one test class annotated as

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

The problem is, when I run "mvn clean test", it seems that all test classes run after the above class fail because the in-memory database is destroyed and not re-created. I get errors like

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) 

Here is how I setup the test class (run after the above class) that gives the exceptions …

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

Is there any way I can restore my application context to its original state before each test class is run? I don't want to make the "TrainingSessionServiceTest" class extend AbstractTransactionalJUnit4SpringContextTests. Here is the relevant part of my application context:

<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>   
like image 257
Dave Avatar asked Feb 05 '13 22:02

Dave


People also ask

How do I refresh application context in spring boot?

For a Spring Boot Actuator application, some additional management endpoints are available. You can use: POST to /actuator/env to update the Environment and rebind @ConfigurationProperties and log levels. /actuator/refresh to re-load the boot strap context and refresh the @RefreshScope beans.

What is the default application context in spring boot?

Overview. Spring Boot, by default, serves content on the root context path (“/”).

What does SpringBootTest annotation do?

The @SpringBootTest annotation loads the complete Spring application context. In contrast, a test slice annotation only loads beans required to test a particular layer. And because of this, we can avoid unnecessary mocking and side effects.

What is @ContextConfiguration in spring test?

@ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.


1 Answers

Use @DirtiesContext to force a reset. For example I have:

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

From spring docs

DirtiesContext

Indicates that the underlying Spring ApplicationContext has been dirtied (modified)as follows during the execution of a test and should be closed, regardless of whether the test passed:

  • After the current test class, when declared on a class with class mode set to AFTER_CLASS, which is the default class mode.

  • After each test method in the current test class, when declared on a class with class mode set to AFTER_EACH_TEST_METHOD.

  • After the current test, when declared on a method.

Use this annotation if a test has modified the context (for example, by replacing a bean definition). Subsequent tests are supplied a new context. [Note] Limitations of @DirtiesContext with JUnit 3.8

> In a JUnit 3.8 environment @DirtiesContext is only supported on methods and thus not at the class level.

You can use @DirtiesContext as a class-level and method-level annotation within the same class. In such scenarios, the ApplicationContext is marked as dirty after any such annotated method as well as after the entire class. If the ClassMode is set to AFTER_EACH_TEST_METHOD, the context is marked dirty after each test method in the class.

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

When an application context is marked dirty, it is removed from the testing framework's cache and closed; thus the underlying Spring container is rebuilt for any subsequent test that requires a context with the same set of resource locations.

like image 122
Lmwangi Avatar answered Sep 19 '22 05:09

Lmwangi