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

Extent Reports V4在Selenium C#中并行测试结果被覆盖的问题求助

解决Extent Reports V4并行测试结果被覆盖的问题

问题根源

  1. 非线程安全的测试实例:test作为类级变量,并行测试时多个线程会覆盖彼此的测试实例,最终只有最后执行的线程结果被记录
  2. 报告文件写入冲突:所有线程同时写入同一个index.html文件,默认模式下会覆盖之前的内容
  3. ExtentReports实例重复创建:如果多个测试类继承DriverHelper,OneTimeSetUp会多次创建ExtentReports实例,导致报告内容被覆盖

修复方案及代码修改

关键修改点:

  • 用ThreadLocal<ExtentTest>存储每个线程的测试实例,避免跨线程覆盖
  • 为ExtentHtmlReporter启用追加模式,允许多线程写入同一报告文件
  • 将ExtentReports改为单例模式,确保整个测试过程只有一个实例

修改后的完整代码:

public class DriverHelper
{
    // 单例ExtentReports实例,确保全局唯一
    private static readonly Lazy<ExtentReports> _extentInstance = new Lazy<ExtentReports>(() =>
    {
        string workingDirectory = Environment.CurrentDirectory;
        string projectDirectory = Directory.GetParent(workingDirectory).Parent.Parent.FullName;
        string reportPath = Path.Combine(projectDirectory, "index.html");
        
        var htmlReporter = new ExtentHtmlReporter(reportPath);
        // 启用追加模式,解决并行写入覆盖问题
        htmlReporter.AppendExisting = true;
        
        var extent = new ExtentReports();
        extent.AttachReporter(htmlReporter);
        extent.AddSystemInfo("Host Name", "Gold end to end");
        extent.AddSystemInfo("Tester", "Arshad");
        
        return extent;
    });

    public static ExtentReports Extent => _extentInstance.Value;
    // ThreadLocal存储每个线程的ExtentTest实例
    public ThreadLocal<ExtentTest> Test = new ThreadLocal<ExtentTest>();
    public ThreadLocal<IWebDriver> Driver = new ThreadLocal<IWebDriver>();

    [OneTimeSetUp]
    public void Setup()
    {
        // 单例已在Lazy中初始化,此处无需重复创建
    }

    [SetUp]
    public void StartBrowser()
    {
        // 为当前线程创建独立的测试实例
        Test.Value = Extent.CreateTest(TestContext.CurrentContext.Test.Name);

        var browserSetup = new BrowserSetup();
        Driver.Value = browserSetup.SetupBrowser();
    }

    [TearDown]
    public void TearDown()
    {
        var status = TestContext.CurrentContext.Result.Outcome.Status;
        var stackTrace = TestContext.CurrentContext.Result.StackTrace;

        DateTime time = DateTime.Now;
        string fileName = $"Screenshot_{time.ToString("h_mm_ss")}.png";

        if (status == TestStatus.Failed)
        {
            Test.Value.Fail("Test failed", CaptureScreenshot(Driver.Value, fileName));
            Test.Value.Log(Status.Fail, $"Test failed with logtrace: {stackTrace}");
        }
        else if (status == TestStatus.Passed)
        {
            Test.Value.Log(Status.Pass, "Test successful");
        }

        Driver.Value.Quit();
        // 移除当前线程的Test实例,避免内存泄漏
        Test.Dispose();
    }

    [OneTimeTearDown]
    public void OneTimeTearDown()
    {
        Extent.Flush();
    }

    public MediaEntityModelProvider CaptureScreenshot(IWebDriver driver, string screenShotName)
    {
        ITakesScreenshot ts = (ITakesScreenshot)driver;
        var screenshot = ts.GetScreenshot().AsBase64EncodedString;

        return MediaEntityBuilder.CreateScreenCaptureFromBase64String(screenshot, screenShotName).Build();
    }
}

额外注意事项

  • 确保NUnit的并行配置正确(在nunit.config中启用并行执行)
  • 截图文件名建议加入线程ID,避免多个线程生成同名截图文件:string fileName = $"Screenshot_{Thread.CurrentThread.ManagedThreadId}_{time.ToString("h_mm_ss")}.png";
  • 单例模式使用Lazy<T>确保线程安全的初始化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 07:24:19