Playwright Java框架:@BeforeClass初始化Page后ITestResult属性全局访问问题
问题根源解析
问题出在**@BeforeClass阶段没有对应的ITestResult实例**。Reporter.getCurrentTestResult()仅在@Test方法执行期间会返回有效实例,而@BeforeClass属于测试类的初始化阶段,此时还未启动具体的测试方法,你拿到的itr其实是null,根本没完成Page的存储操作,所以监听器里调用getAttribute会返回null,进而触发空指针异常。
两种可行解决方案
方案1:用ThreadLocal存储Page(推荐,适配多线程测试)
ThreadLocal可以保证每个测试线程持有独立的Page实例,不管是在@BeforeClass、@BeforeTest还是@Test里初始化,监听器都能直接拿到当前线程的Page。
1. 修改封装方法
在你的封装类中定义ThreadLocal变量,并提供存取、清理方法:
// 定义线程局部变量存储Page private static final ThreadLocal<Page> PAGE_THREAD_LOCAL = new ThreadLocal<>(); public BaseBrowser retrievePage(Browser browser, ThreadLocalContextMap contextMap, BrowserContext browserContext, String contextKey) { if (contextMap.containsKey(contextKey)) { browserContext = contextMap.get(contextKey); } else { browserContext = browser.newContext(new Browser.NewContextOptions().setIgnoreHTTPSErrors(true)); contextMap.put(contextKey, browserContext); } Page scrnShtPg = browserContext.newPage(); // 将Page存入ThreadLocal PAGE_THREAD_LOCAL.set(scrnShtPg); return new BaseBrowser(scrnShtPg); } // 供监听器获取当前线程的Page public static Page getCurrentPage() { return PAGE_THREAD_LOCAL.get(); } // 测试结束后清理ThreadLocal,避免内存泄漏 public static void removeCurrentPage() { PAGE_THREAD_LOCAL.remove(); }
2. 修改自定义监听器
@Override public void onTestFailure(ITestResult iTestResult) { JsonObject element = null; byte[] bufferImage = null; // 从ThreadLocal获取当前Page Page page = YourWrapperClassName.getCurrentPage(); // 替换成你的封装类实际名称 if (page != null) { bufferImage = page.screenshot(); } try { element = SyscoLabReporting.getElement(iTestResult, bufferImage); elements.add(element); } catch (IOException e) { throw new RuntimeException(e); } // 清理当前线程的Page实例 YourWrapperClassName.removeCurrentPage(); }
3. 测试类无需修改
原@BeforeClass的初始化逻辑保持不变即可。
方案2:绑定Page到ITestContext(适合单线程测试)
@BeforeClass方法可以直接拿到ITestContext实例,把Page存到测试类级别的上下文属性中,监听器通过iTestResult.getTestContext()获取。
1. 修改测试类的setUp方法
@BeforeClass(alwaysRun = true) public void setUp(ITestContext iTestContext) throws InterruptedException { page = getPage("Default"); // 将Page存入ITestContext(假设BaseBrowser有方法返回原生Playwright Page实例) iTestContext.setAttribute("Page_Reference", page.getRawPage()); }
2. 修改自定义监听器
@Override public void onTestFailure(ITestResult iTestResult) { JsonObject element = null; byte[] bufferImage = null; // 从测试上下文获取Page ITestContext testContext = iTestResult.getTestContext(); Page page = (Page) testContext.getAttribute("Page_Reference"); if (page != null) { bufferImage = page.screenshot(); } try { element = SyscoLabReporting.getElement(iTestResult, bufferImage); elements.add(element); } catch (IOException e) { throw new RuntimeException(e); } }
注意事项
此方案为测试类级别的上下文存储,多线程并行测试时会存在线程安全问题,仅适合单线程测试场景。
额外提示
- 无论采用哪种方案,测试结束后务必关闭Page和BrowserContext,避免浏览器资源泄漏。
- 如果在
@Test方法内再次调用getPage(),ThreadLocal方案会自动维护当前线程的最新Page实例,无需额外处理。
内容的提问来源于stack exchange,提问作者Kasun Herath
相关产品推荐
相关产品推荐

