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

ExtentReport在NUnit自定义重试后重复显示测试结果,如何仅展示最后一次?

解决NUnit自定义重试下ExtentReport仅展示最后一次结果的方案

我之前也碰到过这个问题——重试几次就生成几条报告记录,看起来特别冗余。核心原因是每次重试都会触发测试的完整生命周期(SetUp→测试方法→TearDown),而默认情况下ExtentReport会为每一次执行都创建独立的测试条目。要实现只展示最后一次结果,我们需要跟踪重试状态,控制ExtentReport的记录时机,具体可以按以下步骤来做:

1. 改造自定义Retry属性,传递重试状态

首先要在你的CustomRetry属性里,把当前重试次数和最大重试次数传递到测试上下文中,这样后续的SetUp/TearDown才能判断是否是最后一次执行。

修改CustomRetry的Execute方法:

public override TestResult Execute(ITestExecutionContext context)
{
    int currentAttempt = 0;
    TestResult finalResult;
    var maxRetries = this.MaxRetries; // 你的自定义属性里的最大重试次数

    do
    {
        // 把当前尝试次数(从0开始)存入测试上下文属性
        context.Test.Properties.Set("CurrentRetryAttempt", currentAttempt);
        context.Test.Properties.Set("MaxRetries", maxRetries);
        
        finalResult = context.Execute();
        currentAttempt++;
    } while (currentAttempt <= maxRetries && finalResult.Status == TestStatus.Failed);

    return finalResult;
}

2. 控制SetUp中的ExtentTest创建逻辑

在SetUp方法里,我们只在最后一次执行时初始化ExtentTest实例,非最后一次重试直接跳过报告初始化:

private ExtentTest _currentTest;

[SetUp]
public void TestSetup()
{
    int currentAttempt = TestContext.CurrentContext.Test.Properties.Get("CurrentRetryAttempt") as int? ?? 0;
    int maxRetries = TestContext.CurrentContext.Test.Properties.Get("MaxRetries") as int? ?? 0;

    // 只有最后一次尝试(不管成功失败)才创建测试报告条目
    if (currentAttempt == maxRetries || maxRetries == 0)
    {
        _currentTest = ExtentManager.Instance.CreateTest(TestContext.CurrentContext.Test.FullName);
    }
    else
    {
        _currentTest = null; // 非最后一次,不记录报告
    }
}

3. 测试方法中仅在最后一次执行时记录步骤

在测试方法里,所有的ExtentReport日志输出都要判断_currentTest是否为null,避免非最后一次重试生成无效日志:

[Test, CustomRetry(3)]
public void SampleTest()
{
    try
    {
        _currentTest?.Info("开始执行测试步骤:打开APP");
        // 你的Selenium/Appium测试逻辑...
        
        // 模拟前两次失败,第三次成功的场景
        if (TestContext.CurrentContext.Test.Properties.Get("CurrentRetryAttempt") as int? < 2)
        {
            Assert.Fail("模拟测试失败");
        }

        _currentTest?.Pass("测试执行成功");
    }
    catch (Exception ex)
    {
        _currentTest?.Fail($"测试失败:{ex.Message}", 
            MediaEntityBuilder.CreateScreenCaptureFromPath("失败截图路径").Build());
        throw; // 必须抛出异常,让NUnit触发下一次重试
    }
}

4. TearDown中仅处理最后一次执行的结果

最后在TearDown里,同样只针对最后一次执行的结果完成报告的刷新:

[TearDown]
public void TestTearDown()
{
    if (_currentTest != null)
    {
        // 兜底处理:如果测试方法里没手动标记状态,根据NUnit结果更新
        if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed && !_currentTest.Status.HasValue)
        {
            _currentTest.Pass("测试最终通过");
        }
        ExtentManager.Instance.Flush();
    }

    // 其他通用收尾操作(关闭驱动等)
    DriverManager.QuitDriver();
}

关键注意点

  • 必须在测试失败时抛出异常,否则NUnit不会触发重试逻辑,你的自定义Retry属性也就不起作用。
  • 如果使用OneTimeTearDown,要注意它只会执行一次,不需要做重试判断,正常处理全局资源清理即可。
  • 确保ExtentManager是单例模式,避免多次初始化导致报告混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:32:42