Java 在测试方法中重新加载或刷新 Spring 应用程序上下文?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24720330/
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-08-14 14:26:05  来源:igfitidea点击:

Reload or refresh a Spring application context inside a test method?

javaspringtestngapplicationcontextspring-test

提问by David E

I need to change the Spring profiles that are active in my applicationContext within a single method of my test class, and to do so I need to run one line of code before refreshing the contest because I am using a ProfileResolver. I have tried the following:

我需要在我的测试类的单个方法中更改在我的 applicationContext 中活动的 Spring 配置文件,为此我需要在刷新比赛之前运行一行代码,因为我使用的是 ProfileResolver。我尝试了以下方法:

@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"})
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {
    @Test
    public void test() throws Exception {
        codeToSetActiveProfiles(...);
        ((ConfigurableApplicationContext)this.applicationContext).refresh();
        ... tests here ...
        codeToSetActiveProfiles(... back to prior profiles ...);
        ... ideally refresh/reload the context for future tests
    }
}

But I get:

但我得到:

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once

DirtiesContext does not work for me because it is run AFTER class/method execution, not before, and I need to execute a line of code prior to running the refresh/reload anyway.

DirtiesContext 对我不起作用,因为它是在类/方法执行之后而不是之前运行的,而且我需要在运行刷新/重新加载之前执行一行代码。

Any suggestions? I tried to have a look through the listeners/hooks that are being run, but I didn't see an obvious location to insert myself to achieve this behavior.

有什么建议?我试图查看正在运行的侦听器/钩子,但我没有看到一个明显的位置来插入自己以实现这种行为。

采纳答案by Sam Brannen

By design, programmatic refreshing of an ApplicationContextis not explicitly supported by the Spring TestContext Framework. Furthermore, it is not intended that a test method refresh a context.

根据设计,ApplicationContextSpring TestContext 框架不明确支持对 an 的编程刷新。此外,测试方法并不打算刷新上下文。

Thus I would recommend that you reassess your need for a refresh and consider alternatives like placing test methods that require a different set of active profiles in a dedicated test class.

因此,我建议您重新评估您的更新需求,并考虑替代方案,例如将需要一组不同活动配置文件的测试方法放在专用测试类中。

In summary, @ActiveProfilessupports declarativeconfiguration (via valueand profilesattributes) and programmaticconfiguration (via the resolverattribute) of the active profiles for tests, but only at the test class level (not at the method level). Another option is to implement an ApplicationContextInitializerand configure that via @ContextConfiguration(initializers=...).

总之,@ActiveProfiles支持测试的活动配置文件的声明式配置(通过valueprofiles属性)和编程配置(通过resolver属性),但仅在测试类级别(不在方法级别)。另一种选择是ApplicationContextInitializer通过@ContextConfiguration(initializers=...).

The only other way to affect the ApplicationContextbeforeit is refreshed is to implement a SmartContextLoaderor extend one of the provided classes and configure it via @ContextConfiguration(loader=...). For example, AbstractGenericContextLoader.customizeContext()allows one to "customize the GenericApplicationContextcreated by the loader afterbean definitions have been loaded into the context but beforethe context is refreshed."

影响刷新ApplicationContext的唯一其他方法是实现SmartContextLoader或扩展提供的类之一并通过@ContextConfiguration(loader=...). 例如,AbstractGenericContextLoader.customizeContext()允许“bean 定义加载到上下文之后但刷新上下文之前自定义GenericApplicationContext由加载器创建的内容”。

Best regards,

此致,

Sam (author of the Spring TestContext Framework)

Sam(Spring TestContext 框架的作者)

回答by Serge Ballesta

Not all application contextes support multiple refresh. According to javadoc for AbstractRefreshableApplicationContextonly subclasses of it or of AbstractRefreshableWebApplicationContextaccept refreshmore than once ... and GenericApplicationContextin not one of them.

并非所有应用程序上下文都支持多个refresh. 根据 javadocAbstractRefreshableApplicationContext仅针对它的子类或不止一次AbstractRefreshableWebApplicationContext接受refresh......而GenericApplicationContext不是其中之一。

You should use another class for your ApplicationContextto support hot refresh.

您应该使用另一个类ApplicationContext来支持热刷新。

Edit :

编辑 :

As you are using @ContextConfigurationannotation, you should use a custom ContextLoaderor SmartContextLoaderimplementation to force spring to use a less stupid ApplicationContext. But I never found a clean and neat way to to that. So when I need a XmlWebApplicationContextin my test classes, I do not use @ContextConfigurationbut create and refresh my context by handin a @Beforemethod or at the beginning of a test.

当您使用@ContextConfiguration注释时,您应该使用自定义ContextLoaderSmartContextLoader实现来强制 spring 使用不那么愚蠢的ApplicationContext. 但我从来没有找到一种干净整洁的方法来做到这一点。因此,当我XmlWebApplicationContext在测试类中需要 a时,我不使用@ContextConfiguration而是在方法中或在测试开始时手动创建和刷新我的上下文@Before

I recognize this does not really answers your question, but you can see it as a workaround.

我承认这并不能真正回答您的问题,但您可以将其视为一种解决方法。

回答by Ivan Pronin

There's a nice little hack to trigger a context refresh - to use org.springframework.cloud.context.refresh.ContextRefresher.

有一个很好的小技巧可以触发上下文刷新 - 使用org.springframework.cloud.context.refresh.ContextRefresher.

I'm not 100% sure this method will suite you: it requiresa spring-cloud-contextdependency. However, this may be added just as a testdependency and not leak into production classpath.

我不是100%肯定这方法适合你:它需要一个spring-cloud-context依赖。但是,这可以作为test依赖项添加,而不会泄漏到生产类路径中。

To use this refresher you also need to import org.springframework.cloud.autoconfigure.RefreshAutoConfigurationconfiguration, which adds a RefreshScopescope to your applicationContextwhich is actually doing the job under the hood.

要使用此复习,您还需要导入org.springframework.cloud.autoconfigure.RefreshAutoConfiguration配置,这RefreshScope为您applicationContext实际上在幕后完成工作的范围添加了一个范围。

So, modify test as follows:

因此,修改测试如下:

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.context.refresh.ContextRefresher;    
// your other imports


@WebAppConfiguration
@ContextConfiguration(locations = {"/web/WEB-INF/spring.xml"}, classes = RefreshAutoConfiguration.class)
@ActiveProfiles(resolver = BaseActiveProfilesResolverTest.class)
public class ControllerTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private ContextRefresher contextRefresher;

    @Test
    public void test() throws Exception {
        // doSmth before
        contextRefresher.refresh();
        // context is refreshed - continue testing
    }

}