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

基于extentreports-testng-adapter:Cucumber+TestNG失败用例截图添加至HTML报告

解决方案:Cucumber场景失败时自动附加截图到Extent Report(兼容并行测试)

我明白你的情况:用Cucumber+Selenium+TestNG搭的框架,靠extentreports-testng-adapter自动生成报告,没写额外的Extent代码,还得支持并行测试,现在就差失败场景自动加截图这一步。下面给你一套完美适配的方案:

步骤1:编写自定义Extent监听器

既然你已经在用ExtentITestListenerAdapter,我们直接继承它,重写测试失败时的处理逻辑即可。这个监听器会在每个Cucumber场景(对应TestNG的测试方法)失败时触发,我们在里面嵌入截图逻辑:

import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.testng.listener.ExtentITestListenerAdapter;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;

public class CustomExtentListener extends ExtentITestListenerAdapter {

    @Override
    public void onTestFailure(ITestResult result) {
        // 先调用父类的失败处理逻辑,保留原有日志输出
        super.onTestFailure(result);

        // 从测试实例中获取WebDriver——这里假设你的Step类用ThreadLocal存储驱动(并行测试必备)
        Object testInstance = result.getInstance();
        WebDriver driver = ((YourBaseStepClass) testInstance).getDriver();

        if (driver != null) {
            // 生成base64格式的截图(无需存本地,直接嵌入报告)
            String base64Screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
            
            // 将截图附加到当前对应的Extent测试条目
            getExtentTest().fail("场景失败截图",
                MediaEntityBuilder.createScreenCaptureFromBase64String(base64Screenshot).build());
        }
    }
}

并行测试核心注意事项

必须用ThreadLocal管理WebDriver,避免并行时多个场景争抢同一个驱动实例。比如在你的基础Step类中这么实现:

public class YourBaseStepClass {
    // 为每个线程独立存储WebDriver实例
    private static final ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>();

    public WebDriver getDriver() {
        return driverThreadLocal.get();
    }

    public void setDriver(WebDriver driver) {
        driverThreadLocal.set(driver);
    }
}

另外,父类提供的getExtentTest()方法会自动返回当前线程对应的ExtentTest实例,完全不用担心并行测试时报告串图的问题。

步骤2:替换测试类中的监听器配置

把原来的ExtentITestListenerAdapter换成我们刚写的自定义监听器即可:

@CucumberOptions(
    features = { "src/test/resources/common_features/test.feature" },
    glue = { "com.step.definitions" },
    tags = {},
    plugin = {},
    monochrome = true,
    dryRun = false 
) 
@Listeners({CustomExtentListener.class}) // 替换为自定义监听器
public class TestCase extends AbstractTestNGCucumberTests { } 

备选方案:结合Cucumber的@After钩子实现

如果你更习惯用Cucumber的钩子体系处理,也可以采用这个方案:

import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.testng.listener.ExtentITestListenerAdapter;
import io.cucumber.java.After;
import io.cucumber.java.Scenario;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

public class Hooks {
    private final WebDriver driver;
    private final ExtentITestListenerAdapter extentListener;

    // 通过Cucumber默认支持的依赖注入(如PicoContainer)获取实例
    public Hooks(WebDriver driver, ExtentITestListenerAdapter extentListener) {
        this.driver = driver;
        this.extentListener = extentListener;
    }

    @After
    public void afterScenario(Scenario scenario) {
        if (scenario.isFailed()) {
            String base64Screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
            // 为当前失败的场景附加截图
            extentListener.getExtentTest().fail("场景失败截图",
                MediaEntityBuilder.createScreenCaptureFromBase64String(base64Screenshot).build());
        }
    }
}

这个方案的优势是逻辑和Cucumber的钩子体系结合更紧密,同样要注意用ThreadLocal管理WebDriver以支持并行测试。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:29:25