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

Dav*_*d E 12 java testng spring spring-test applicationcontext

我需要在我的测试类的单个方法中更改我的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
    }
}
Run Code Online (Sandbox Code Playgroud)

但我得到:

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
Run Code Online (Sandbox Code Playgroud)

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

有什么建议?我试着看一下正在运行的监听器/钩子,但是我没有看到一个明显的位置来插入自己来实现这种行为.

Sam*_*nen 14

通过设计,ApplicationContextSpring TestContext Framework没有明确支持程序刷新.此外,测试方法并不打算刷新上下文.

因此,我建议您重新评估是否需要刷新,并考虑在专用测试类中放置需要不同活动配置文件集的测试方法等替代方案.

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

刷新ApplicationContext 之前影响之前的唯一方法是实现SmartContextLoader或扩展其中一个提供的类并通过它进行配置@ContextConfiguration(loader=...).例如,AbstractGenericContextLoader.customizeContext()允许一个" 在将 bean定义加载到上下文之后但刷新上下文之前 "自定义GenericApplicationContext由加载器创建的.

最好的祝福,

Sam(Spring TestContext Framework的作者)


小智 6

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

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

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

因此,修改测试如下:

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
    }

}
Run Code Online (Sandbox Code Playgroud)