在 JUnit 5 中超过超时后如何使测试失败?

How to fail a test after a timeout is exceeded in JUnit 5?

在 JUnit 4 中,"timeout" 注释参数可用于强制测试在给定时间后停止:

@Test(timeout=100)
public void infinity() {
   while(true);
}

如何在 JUnit 5 中完成此操作?

timeout parameter for Annotation Type Test 密切相关(代码取自)timeout parameter for Annotation Type Test,但适用于 JUnit 5。

使用来自 org.junit.jupiter.api.AssertionsassertTimeoutPreemptively 静态断言:

@Test
public void infinity() {
    assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
        while (true);
    });
}

timeout 属性的严格等价物是声明性 @Timeout 注释。
From the JUnit 5 documentation :

The @Timeout annotation allows one to declare that a test, test factory, test template, or lifecycle method should fail if its execution time exceeds a given duration. The time unit for the duration defaults to seconds but is configurable.

例如:

@Test
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
void infinity() { 
  // fails if execution time exceeds 100 milliseconds
  //...
}

Assertions.assertTimeout() and Assertions.assertTimeoutPreemptively() 是 JUnit 5 中引入的新概念(JUnit 4 中不存在)。 这些是 @Timeout 的替代方法,将超时缩小到一组特定的语句:这些在 ExecutableSupplier 中定义为参数传递。
这两种方法(名称非常接近)解决了相同的总体目标,但有细微的差别。
如果超时发生,assertTimeoutPreemptively() 抢先中止 Executable/Supplier,而 assertTimeout() 没有。
为了实现它,assertTimeoutPreemptively() 在与调用代码不同的线程中执行提供的 Executable/Supplier,而 assertTimeout() 在同一线程中执行它。

来自官方文档的警告: Code/libraries 依赖 java.lang.ThreadLocal 存储进行测试执行 setup/teardown 可能会对 assertTimeoutPreemptively() 产生不良副作用,因为它会在不同的线程中执行提供的语句。

除了为特定测试指定超时的其他答案(根据 OP 请求),从 JUnit 5.5 开始,还可以配置全局超时,这是一个有用的选项,而不是添加 @Timeout 每个方法的注释。

根据 JUnit 5 User Guide,它记录了其他答案中的语法:

configuration parameters can be used to specify global timeouts for all methods of a certain category unless they or an enclosing test class is annotated with @Timeout

例如,这将为所有可测试和生命周期方法设置 500 毫秒的全局超时:

junit.jupiter.execution.timeout.default = 500 ms

超时的范围可以更窄,例如 @Test 方法:

junit.jupiter.execution.timeout.testtemplate.method.default = 500 ms

如果使用其他答案中描述的 @Timeout 注释,将覆盖这些默认值。