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

TestNG报告中标记为跳过的重试测试未被移除,求代码问题排查

问题分析与解决方案

你遇到的核心问题是:重试后的测试记录(标记为SKIPPED的重试尝试)仍被计入TestNG报告统计,导致Jenkins里的测试总数包含冗余的重试记录。你的代码存在以下几个关键问题:

1. 遍历集合时的并发修改异常

直接用增强for循环遍历Set<ITestResult>并执行remove操作,会触发ConcurrentModificationException,导致清理逻辑未完整执行,冗余记录自然无法被移除。

2. 清理逻辑不完整

代码仅处理了SkippedTests,但重试过程中第一次失败的记录会被留在FailedTests中(即使重试后测试通过);同时判断逻辑存在漏洞,无法正确识别重试产生的冗余记录。


修正后的代码

修正后的TestListenerAdapter

package generics;

import java.util.Iterator;
import java.util.List;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;

public class TestListenerAdapter extends org.testng.TestListenerAdapter {

    @Override
    public void onFinish(ITestContext context) {
        // 清理失败测试中的冗余重试记录
        cleanRedundantResults(context.getFailedTests().getAllMethods(), context);
        // 清理跳过测试中的冗余重试记录
        cleanRedundantResults(context.getSkippedTests().getAllMethods(), context);
    }

    private void cleanRedundantResults(List<ITestNGMethod> methods, ITestContext context) {
        for (ITestNGMethod method : methods) {
            List<ITestResult> results = context.getResults(method);
            if (results.size() <= 1) {
                continue; // 仅一条记录,无需清理
            }
            // 保留最后一条结果(重试后的最终状态),移除之前的重试记录
            ITestResult finalResult = results.get(results.size() - 1);
            Iterator<ITestResult> iterator = results.iterator();
            while (iterator.hasNext()) {
                ITestResult result = iterator.next();
                if (!result.equals(finalResult)) {
                    // 从对应集合中移除冗余记录
                    if (result.getStatus() == ITestResult.FAILURE) {
                        context.getFailedTests().removeResult(result);
                    } else if (result.getStatus() == ITestResult.SKIP) {
                        context.getSkippedTests().removeResult(result);
                    }
                    iterator.remove();
                }
            }
        }
    }
}

补充优化(可选)

如果你的测试是并行执行的,原RetryAnalyzer的retryCount存在线程安全问题,可改为用ThreadLocal存储计数:

package generics;

import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;

public class RetryAnalyzer implements IRetryAnalyzer {

    private ThreadLocal<Integer> retryCount = ThreadLocal.withInitial(() -> 0);
    private int maxRetryCount = 1;

    @Override
    public boolean retry(ITestResult result) {
        int currentCount = retryCount.get();
        if (currentCount < maxRetryCount) {
            retryCount.set(currentCount + 1);
            return true;
        }
        retryCount.remove(); // 重置线程变量
        return false;
    }
}

额外注意事项

你的testng.xml监听类配置顺序是正确的(注解转换器TestTranformer需在监听类之前加载),无需调整。

内容的提问来源于stack exchange,提问作者dai123456va

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:32:41