将 jUnit 超时与 @DirtiesContext 相结合

Combine jUnit timeout with @DirtiesContext

我有一个测试用例可以修改我的 spring 上下文,并且可能 运行 进入无限循环。在测试用例之后,我想要一个干净的 spring 上下文,所以我使用了 @DirtiesContext 注释。在无限循环的情况下,我添加了一个 jUnit 超时。

@Test(timeout = 1000)
@DirtiesContext
public void testTimeout() {
    //test stuff
}

问题是,如果测试 运行 超时,jUnit 似乎会以 spring 不再处理上下文重置的方式终止它。如果我在 class 级别上添加 @DirtiesContext,则行为相同。

还有其他方法可以实现我想要做的事情吗?

我设法解决了我的问题。我将 spring 升级到 4.2.0,它已经发布了大约一周,它支持在方法之前清理上下文。

@Test(timeout = 1000)
@DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
public void testTimeout() {
    //test stuff
}

这样测试仍然会在超时后终止,但上下文会在下一个方法之前被清除。猜想这样我每次测试都有一个不必要的上下文初始化 class 但它有效。

要使用 JUnit 和 Spring TestContext Framework (TCF) 配置 timeout,您有两个主要类别选项:

  1. preemptive:如果您使用 JUnit 的 Timeout 规则或 @Testtimeout 属性,您的测试和所有嵌套规则,关联before/after 方法、TCF 回调等将在单独的线程中执行,如果 timeout 已超出。
  2. 非抢占式:如果您将 Spring 的 @Timed 注释与 TCF 一起使用,您的测试和所有嵌套规则,关联 before/after 方法、TCF 回调等将在与测试运行器相同的线程中执行,测试只有在正常终止且超时 已超过。

Timeout 规则和 @Testtimeout 属性都会导致在幕后使用 FailOnTimeout 语句; FailOnTimeout 在一个单独的线程中执行链中的下一条语句,如果超过超时,该线程将被抢先终止。因此,这两个基于 JUnit 的配置选项的行为自然是相同的:语句链的执行提前结束,没有给任何 after 回调执行其任务的机会。结果是 Spring 的 DirtiesContextTestExecutionListener 中的 afterTestMethod() 回调在这种情况下永远不会被调用,因此上下文不会是 .

Is there another way to achieve what I'm trying to do?

对于初学者,使用 Spring 的 @Timed 注释不适合您,因为它不会抢先中止在无限循环中运行的代码。

您提到您通过使用 Spring Framework 4.2 中引入的 @DirtiesContext(methodMode = BEFORE_METHOD) 功能发现了一个解决方法。 可能在某些情况下工作,但这种变通办法充其量是脆弱的:使用这种变通办法会导致上下文在[=63=之前关闭并重新启动] 这个 特定的方法;但是,如果有问题的代码在抢占式超时之前修改了上下文,您的 Spring 上下文对于后续测试方法将保持损坏。

唯一真正的解决方案是确保在next上使用@DirtiesContextBEFORE_METHOD模式] 方法 由于超时而被抢先中止的方法之后执行。然而...确切知道哪种方法是 "next" 方法可能是具有挑战性的部分...除非您使用 JUnit 的 @FixMethodOrder 支持。

此致,

Sam(Spring TestContext Framework 的作者)