在测试类之前和之后使ApplicationContext变脏

dty*_*dty 12 java spring spring-test

MyTest在我的Spring集成测试中有一个特定的类(比方说),它@PrepareForTest在Spring组件上使用PowerMock 注释:@PrepareForTest(MyComponent.class).这意味着PowerMock将通过一些修改加载此类.问题是,我@ContextConfiguration是在扩展的超类上定义的MyTest,并且ApplicationContext是在不同的测试类之间缓存的.现在,如果MyTest先运行,它将具有正确的PowerMock版本MyComponent,但如果没有 - 测试将失败,因为上下文将被加载以进行另一次测试(没有@PrepareForTest).

所以我想要做的是重新加载我的上下文MyTest.我可以通过这样做

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
Run Code Online (Sandbox Code Playgroud)

但是,如果我还想在完成此测试后重新加载上下文怎么办?所以我会在MyComponent没有PowerMock修改的情况下再次清理.有没有办法做到既BEFORE_CLASSAFTER_CLASS

现在我用以下黑客做到了:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
Run Code Online (Sandbox Code Playgroud)

在MyTest然后

/**
 * Stub test to reload ApplicationContext before execution of real test methods of this class.
 */
@DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
@Test
public void aa() {
}

/**
 * Stub test to reload ApplicationContext after execution of real test methods of this class.
 */
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
@Test
public void zz() {
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更漂亮的方法吗?

作为一个附带问题,是否可以仅重新加载某些bean而不是完整的上下文?

Sam*_*nen 11

有没有办法同时做BEFORE_CLASS和AFTER_CLASS?

不,遗憾的是,不支持@DirtiesContext.

但是,你真正要说的是你想要一个新ApplicationContextMyTest,与父测试类的上下文相同,但只有生命MyTest.而且......您不希望影响父测试类缓存的上下文.

所以考虑到这一点,以下技巧应该可以胜任.

@RunWith(SpringJUnit4ClassRunner.class)
// Inherit config from parent and combine with local 
// static Config class to create a new context
@ContextConfiguration
@DirtiesContext
public class MyTest extends BaseTests {

    @Configuration
    static class Config {
        // No need to define any actual @Bean methods.
        // We only need to add an additional @Configuration
        // class so that we get a new ApplicationContext.
    }
}
Run Code Online (Sandbox Code Playgroud)

@DirtiesContext的替代品

如果您希望测试类之前之后弄脏上下文,则可以实现TestExecutionListener完全相同的自定义.例如,以下将做到这一点.

import org.springframework.core.Ordered;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;

public class DirtyContextBeforeAndAfterClassTestExecutionListener
        extends AbstractTestExecutionListener {

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public void beforeTestClass(TestContext testContext) throws Exception {
        testContext.markApplicationContextDirty(HierarchyMode.EXHAUSTIVE);
    }

    @Override
    public void afterTestClass(TestContext testContext) throws Exception {
        testContext.markApplicationContextDirty(HierarchyMode.EXHAUSTIVE);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以MyTest按如下方式使用自定义侦听器.

import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.TestExecutionListeners.MergeMode;

@TestExecutionListeners(
    listeners = DirtyContextBeforeAndAfterClassTestExecutionListener.class, 
    mergeMode = MergeMode.MERGE_WITH_DEFAULTS
)
public class MyTest extends BaseTest { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

作为一个附带问题,是否可以仅重新加载某些bean而不是完整的上下文?

不,这也是不可能的.

问候,

Sam(Spring TestContext Framework的作者)