在测试类弄脏 Spring JUnit 应用程序上下文后,如何重置它?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14718088/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:42:21  来源:igfitidea点击:

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

springjunithsqldbapplicationcontext

提问by Dave

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

我正在使用 Spring 3.1.1.RELEASE、JUnit 4.8.1 和 HSQL 2.7.7 内存数据库。我有一个测试类注释为

@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

问题是,当我运行“mvn clean test”时,似乎在上述类之后运行的所有测试类都失败了,因为内存数据库被破坏而不是重新创建。我收到类似的错误

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.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:

在每个测试类运行之前,有什么方法可以将我的应用程序上下文恢复到其原始状态?我不想让“TrainingSessionServiceTest”类扩展 AbstractTransactionalJUnit4SpringContextTests。这是我的应用程序上下文的相关部分:

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

回答by Lmwangi

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

使用@DirtiesContext 强制重置。例如我有:

@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

来自spring 文档

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:

表示底层 Spring ApplicationContext 在测试执行过程中被污染(修改)如下,应该关闭,无论测试是否通过:

  • 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.

  • 在当前测试类之后,当在类模式设置为 AFTER_CLASS 的类上声明时,这是默认的类模式。

  • 在当前测试类中的每个测试方法之后,当在类模式设置为 AFTER_EACH_TEST_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

如果测试修改了上下文(例如,通过替换 bean 定义),请使用此注释。随后的测试提供了一个新的上下文。[注意] @DirtiesContext 与 JUnit 3.8 的限制

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

> 在 JUnit 3.8 环境中,@DirtiesContext 仅在方法上受支持,因此在类级别不受支持。

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 用作同一类中的类级和方法级注释。在这种情况下,ApplicationContext 在任何此类带注释的方法之后以及整个类之后都被标记为脏。如果 ClassMode 设置为 AFTER_EACH_TEST_METHOD,则在类中的每个测试方法之后将上下文标记为脏。

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

当应用程序上下文被标记为脏时,它会从测试框架的缓存中移除并关闭;因此,对于需要具有相同资源位置集的上下文的任何后续测试,都会重新构建底层 Spring 容器。