TestNG结合Cucumber自定义报告:单步骤执行时长统计方案问询
TestNG 场景内单步骤执行时长统计实现方案
你目前用的ITestContext的getStartMillis/getEndMillis只能拿到整个测试场景的执行周期,要统计单步骤时长,需要在步骤执行的前后插入计时埋点,以下是两种可落地的实现方案:
方案1:监听器+自定义注解(无侵入测试代码)
适合测试用例量大、不想修改原有测试逻辑的场景,利用TestNG的扩展监听机制自动统计所有标记的步骤时长:
- 首先定义
@TestStep注解,用来标记属于单步骤的方法:
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TestStep { // 步骤显示名称,用于报告展示 String value(); }
- 实现
IInvokedMethodListener监听器,自动记录每个被标记步骤的起止时间:
import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class StepTimingListener implements IInvokedMethodListener { // 线程隔离存储单步骤开始时间,避免多线程执行测试时数据冲突 private final ThreadLocal<Long> stepStartTimestamp = new ThreadLocal<>(); // 全局存储所有步骤的时长,Key格式:场景名称-步骤名称,Value为时长(单位:毫秒) public static final Map<String, Long> STEP_DURATION_STORAGE = new ConcurrentHashMap<>(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { Method currentMethod = method.getTestMethod().getConstructorOrMethod().getMethod(); // 仅处理标记了@TestStep注解的步骤方法 if (currentMethod.isAnnotationPresent(TestStep.class)) { stepStartTimestamp.set(System.currentTimeMillis()); } } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { Method currentMethod = method.getTestMethod().getConstructorOrMethod().getMethod(); if (currentMethod.isAnnotationPresent(TestStep.class)) { Long startTime = stepStartTimestamp.get(); if (startTime != null) { long duration = System.currentTimeMillis() - startTime; String sceneName = testResult.getTestContext().getName(); String stepName = currentMethod.getAnnotation(TestStep.class).value(); STEP_DURATION_STORAGE.put(String.format("%s-%s", sceneName, stepName), duration); // 清除ThreadLocal数据避免内存泄漏 stepStartTimestamp.remove(); } } } }
- 最后注册监听器:可以在TestNG的xml配置文件中添加
<listeners>标签引入该类,或者直接在测试类上添加@Listeners(StepTimingListener.class)注解即可生效。
方案2:手动埋点(轻量快速实现)
适合测试用例量小、需要快速上线统计能力的场景,直接在测试逻辑中插入计时代码:
import org.testng.ITestContext; import org.testng.annotations.Test; public class TestDemo { @Test public void testOrderScene(ITestContext context) { String sceneName = context.getName(); // 步骤1:提交订单 long step1Start = System.currentTimeMillis(); orderService.submitOrder(); long step1Duration = System.currentTimeMillis() - step1Start; // 将时长存入当前场景的上下文,后续报告生成时可直接读取 context.setAttribute("step1_提交订单", step1Duration); // 步骤2:支付订单 long step2Start = System.currentTimeMillis(); payService.pay(); long step2Duration = System.currentTimeMillis() - step2Start; context.setAttribute("step2_支付订单", step2Duration); } }
报告适配说明
如果使用TestNG默认报告,可以实现IReporter接口,遍历STEP_DURATION_STORAGE或者ITestContext中存储的步骤时长,写入报告的自定义模块即可;如果使用Allure测试报告,框架本身已经对@Step注解标记的方法自带时长统计能力,无需额外开发计时逻辑。
内容的提问来源于stack exchange,提问作者Quest
相关产品推荐
相关产品推荐

