You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 19:06:02