JUnit5中如何为测试类内所有测试用例设置统一超时时间
JUnit5实现类级别统一超时配置方案
场景1:需要类下所有测试方法单独应用相同时长超时
JUnit5原生@Timeout注解本身支持类级别标注,注解加在类上时,会自动为当前类下所有测试方法、@BeforeEach/@AfterEach等生命周期方法统一应用超时规则,无需逐个方法配置。
import org.junit.jupiter.api.Timeout; import java.util.concurrent.TimeUnit; // 类下所有测试方法单独执行时,超时阈值均为200ms @Timeout(value = 200, unit = TimeUnit.MILLISECONDS) class FileLoadTest { // 1000余个测试用例无需单独加@Timeout,自动继承类上的配置 @Test void testLoadFileA() { // 测试逻辑 } }
如果需要给全局所有测试类统一配置默认超时,不需要修改任何测试类代码,直接在测试资源目录下添加junit-platform.properties文件(路径为src/test/resources/junit-platform.properties),添加配置项:
junit.jupiter.execution.timeout.default=200ms
场景2:需要整个测试类所有用例累计执行总时长超时(和JUnit4 @ClassRule Timeout逻辑完全一致)
上面的类级@Timeout是每个测试方法单独计算超时时间,如果需要和原JUnit4 @ClassRule逻辑一致,限制整个类所有测试用例加起来的总执行时长,可以通过自定义JUnit5扩展实现:
- 编写类级总超时扩展
import org.junit.jupiter.api.extension.*; import java.lang.reflect.Method; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; public class ClassTotalTimeoutExtension implements BeforeAllCallback, InvocationInterceptor { private final long timeoutThresholdMs; private final AtomicLong remainingMs; private final ExecutorService timeoutExecutor = Executors.newSingleThreadExecutor(); public ClassTotalTimeoutExtension(long timeoutThresholdMs) { this.timeoutThresholdMs = timeoutThresholdMs; this.remainingMs = new AtomicLong(timeoutThresholdMs); } @Override public void beforeAll(ExtensionContext context) { remainingMs.set(timeoutThresholdMs); } @Override public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable { long currentRemaining = remainingMs.get(); if (currentRemaining <= 0) { throw new TimeoutException("测试类累计执行时长已超过" + timeoutThresholdMs + "ms限制"); } Future<Void> runningTask = timeoutExecutor.submit(() -> { invocation.proceed(); return null; }); long startTime = System.currentTimeMillis(); try { runningTask.get(currentRemaining, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { runningTask.cancel(true); throw new TimeoutException("测试类累计执行时长已超过" + timeoutThresholdMs + "ms限制"); } catch (ExecutionException e) { throw e.getCause(); } finally { long costTime = System.currentTimeMillis() - startTime; remainingMs.addAndGet(-costTime); if (remainingMs.get() <= 0) { timeoutExecutor.shutdownNow(); } } } }
- 在测试类中注册扩展即可生效
class FileLoadTest { // 等效于原JUnit4的@ClassRule配置 @RegisterExtension static ClassTotalTimeoutExtension classTotalTimeout = new ClassTotalTimeoutExtension(200); // 所有测试用例 }
如果需要批量给所有测试类应用这个扩展,不需要逐个类注册,可以通过JUnit5的SPI自动注册机制:在src/test/resources/META-INF/services目录下创建名为org.junit.jupiter.api.extension.Extension的文件,文件内容填写扩展类的全限定类名,扩展就会自动对所有测试类生效。
内容的提问来源于stack exchange,提问作者dzieciou
相关产品推荐
相关产品推荐

