TestNG集成Extent Reports时@Test方法内调用ExtentTest.log报空指针异常
问题根因
你遇到的空指针问题核心原因是TestNG的监听器实例与测试用例类实例是两个完全独立的对象:虽然Listeners和你的测试类都继承了baseTests,但二者各自持有独立的test成员变量,你在监听器的onTestStart方法中仅对监听器实例自己的test变量做了初始化,测试类中的test变量没有被赋值,因此调用时触发空指针。
解决方案:使用ThreadLocal存储ExtentTest实例
推荐用静态ThreadLocal容器存储ExtentTest,既可以解决跨实例取值的问题,也能兼容多线程并行执行测试的场景,避免多个测试用例的日志互相串扰。
1. 修改baseTests.java
把test变量改为静态ThreadLocal类型:
package base; import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ExtentTest; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import java.io.IOException; public class baseTests { public static ExtentReports extent = ExtentReporterNG.getReportObject(); // 用ThreadLocal存储每个测试线程对应的ExtentTest实例 public static ThreadLocal<ExtentTest> test = new ThreadLocal<>(); @BeforeMethod public void setUp() throws IOException { // 原有测试初始化代码保留 } @AfterMethod public void tearDown() { // 测试结束后清除ThreadLocal,避免内存泄漏 test.remove(); } }
2. 修改Listeners.java
监听器中创建ExtentTest实例后,存入baseTests的ThreadLocal容器中:
package base; import com.aventstack.extentreports.Status; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class Listeners implements ITestListener { // 不需要再继承baseTests,直接访问静态变量即可 @Override public void onTestStart(ITestResult result) { ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName()); // 将创建的test实例存入当前线程对应的ThreadLocal baseTests.test.set(extentTest); } @Override public void onTestSuccess(ITestResult result) { baseTests.test.get().log(Status.PASS, "Test Passed"); } @Override public void onTestFailure(ITestResult result) { baseTests.test.get().fail(result.getThrowable()); } @Override public void onFinish(ITestContext context) { extent.flush(); } }
3. 修改测试类中调用test的写法
从ThreadLocal中取出当前线程对应的ExtentTest实例再调用日志方法:
package test; import base.baseTests; import com.aventstack.extentreports.Status; import org.testng.annotations.Test; import pages.*; public class myTest extends baseTests { @Test public void test1(){ // 原有测试代码保留 test.get().log(Status.PASS, "Some test step"); // 断言语句保留 } }
补充说明
- 无需改动原有的ExtentReporterNG.java代码
- 该方案支持并行测试,每个测试线程的日志会独立存储不会混淆
- 记得在testng.xml中正确配置Listeners监听器,否则监听器的回调方法不会触发
内容的提问来源于stack exchange,提问作者slayerette
相关产品推荐
相关产品推荐

