如何让JUnit统计含@BeforeAll的测试类完整执行时长?
如何让JUnit统计测试类完整生命周期时长(包含@BeforeAll/@AfterAll)
方法一:自定义JUnit 5扩展
JUnit 5的扩展机制能直接拦截测试类的生命周期,手动统计时长:
- 写个扩展类实现
BeforeAllCallback和AfterAllCallback接口,在beforeAll方法里记录测试类启动的时间戳,afterAll里计算总耗时并输出 - 示例代码:
import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; public class ClassLifecycleTimingExtension implements BeforeAllCallback, AfterAllCallback { private static final String START_TIME_KEY = "classStartTime"; @Override public void beforeAll(ExtensionContext context) { long startTime = System.currentTimeMillis(); context.getStore(ExtensionContext.Namespace.GLOBAL).put(START_TIME_KEY, startTime); } @Override public void afterAll(ExtensionContext context) { long startTime = context.getStore(ExtensionContext.Namespace.GLOBAL).get(START_TIME_KEY, Long.class); long totalTime = System.currentTimeMillis() - startTime; System.out.printf("测试类[%s]完整生命周期耗时:%d ms%n", context.getRequiredTestClass().getName(), totalTime); } }
- 使用时,要么在测试类上加
@ExtendWith(ClassLifecycleTimingExtension.class),要么在src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension里写扩展类的全限定名,让所有测试类自动生效
方法二:通过Gradle测试配置统计
直接在Gradle的build.gradle里加监听逻辑,捕捉测试类的启动和结束事件:
test { def classStartTimes = [:] beforeTest { descriptor -> // 只有测试类的descriptor没有父节点 if (descriptor.parent == null) { classStartTimes[descriptor.className] = System.currentTimeMillis() } } afterTest { descriptor, result -> if (descriptor.parent == null) { long totalTime = System.currentTimeMillis() - classStartTimes[descriptor.className] println "测试类 ${descriptor.className} 总耗时:${totalTime} ms" // 要是想存到文件里,直接写文件操作就行 } } }
执行gradle test的时候,控制台就会打印每个测试类的完整耗时,包括@BeforeAll和@AfterAll的时间
方法三:用JUnit 5的TestExecutionListener
注册全局监听类,监听测试类的启动和结束事件:
- 实现
TestExecutionListener接口,重写testClassStarted和testClassFinished方法:
import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestExecutionResult; import java.util.HashMap; import java.util.Map; public class ClassTimingListener implements TestExecutionListener { private final Map<String, Long> classStartTimes = new HashMap<>(); @Override public void testClassStarted(TestIdentifier testIdentifier) { if (testIdentifier.isTestClass()) { classStartTimes.put(testIdentifier.getUniqueId(), System.currentTimeMillis()); } } @Override public void testClassFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { if (testIdentifier.isTestClass()) { long startTime = classStartTimes.get(testIdentifier.getUniqueId()); long totalTime = System.currentTimeMillis() - startTime; System.out.printf("测试类 %s 完整耗时:%d ms%n", testIdentifier.getDisplayName(), totalTime); } } }
- 注册方式:要么在
src/test/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener里写监听类全限定名,要么在Gradle配置里加:
test { junitPlatform { listeners { add 'com.example.ClassTimingListener' } } }
如果想把这些时长整合到Gradle默认的HTML报告里,得自定义报告模板或者扩展现有报告,这个相对麻烦,上面的方法先解决统计问题没问题。
内容的提问来源于stack exchange,提问作者bsohdam
相关产品推荐
相关产品推荐

