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

我需要在我的测试类的单个方法中更改在我的应用程序Context中处于活动状态的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
    }
}

但我得到:

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

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

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


答案 1

根据设计,Spring TestContext Framework 并不明确支持 编程刷新 。此外,测试方法不应刷新上下文。ApplicationContext

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

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

在刷新之前影响 的唯一其他方法是实现或扩展提供的类之一,并通过 对其进行配置。例如,允许“在将 Bean 定义加载到上下文中之后但在刷新上下文之前自定义加载程序创建的。ApplicationContextSmartContextLoader@ContextConfiguration(loader=...)AbstractGenericContextLoader.customizeContext()GenericApplicationContext

此致敬意

Sam(Spring TestContext Framework的作者)


答案 2

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

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

要使用此刷新程序,您还需要导入配置,这会向实际执行后台工作的范围添加一个范围。org.springframework.cloud.autoconfigure.RefreshAutoConfigurationRefreshScopeapplicationContext

因此,请按如下方式修改测试:

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
    }

}

推荐