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

时间:2014-07-13 07:06:33

标签: java spring testng applicationcontext spring-test

我需要在我的测试类的单个方法中更改我的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
    }
}

但我明白了:

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

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

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

3 个答案:

答案 0 :(得分:14)

按照设计,Spring TestContext Framework并未明确支持程序刷新ApplicationContext。此外,测试方法并不打算刷新上下文。

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

总之,@ActiveProfiles支持声明性配置(通过valueprofiles属性)和编程配置(通过{测试的活动配置文件的{1}}属性,但仅限于测试类级别(不在方法级别)。另一种方法是实施resolver并通过ApplicationContextInitializer进行配置。

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

致以最诚挚的问候,

Sam(Spring TestContext Framework的作者)

答案 1 :(得分:0)

并非所有应用程序上下文都支持多个refresh。根据{{​​1}}的javadoc,只有AbstractRefreshableApplicationContext的子类或AbstractRefreshableWebApplicationContext不止一次接受refresh ... GenericApplicationContext而不是其中之一。

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

编辑:

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

我知道这并没有真正回答你的问题,但你可以将其视为一种解决方法。

答案 2 :(得分:0)

有一个不错的小技巧可以触发上下文刷新-使用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
    }

}