Playwright+Java+TestNG框架执行测试时出现连接关闭错误
问题分析与解决方案
核心问题
DriverFactory类的getPage方法使用try-with-resources语法创建Playwright实例,该语法会在try代码块执行完毕后自动调用Playwright.close(),导致返回的Page对象关联的Playwright连接被提前关闭,后续调用page.navigate()时就会抛出Playwright connection closed异常。
修复步骤
1. 调整Playwright实例的生命周期
将Playwright实例提升为类成员变量,避免被自动关闭,在测试结束时手动销毁资源。修改DriverFactory类:
public class DriverFactory { public static ThreadLocal<Page> currentPage = new ThreadLocal<>(); public Page page = null; private PropertyReader propertyReader = new PropertyReader(); Environment environment; // 把Playwright设为类成员,手动控制生命周期 private Playwright playwright; public DriverFactory() { environment = propertyReader.getEnvironment(); } public Page getCurrentPage() { page = currentPage.get(); return page != null ? page : null; } public void initializeBrowser(){ currentPage.set(getPage(environment.getPlatform())); } public Page getPage(String browserName) { // 移除try-with-resources,手动创建Playwright playwright = Playwright.create(); Browser browser = null; if (browserName.equalsIgnoreCase("Chrome")) { browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false)); page = browser.newPage(); } else if (browserName.equalsIgnoreCase("Firefox")) { browser = playwright.firefox().launch(); page = browser.newPage(); } else if (browserName.equalsIgnoreCase("edge")) { browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("msedge")); page = browser.newPage(); } else if (browserName.equalsIgnoreCase("safari")) { browser = playwright.webkit().launch(); page = browser.newPage(); } System.out.println("Page ID " + page); return page; } // 添加销毁方法,在测试结束时关闭资源 public void destroy() { Page page = currentPage.get(); if (page != null) { page.close(); currentPage.remove(); } if (playwright != null) { playwright.close(); } } }
2. 确保WrapperMethods复用同一个DriverFactory实例
当前WrapperMethods构造方法每次新建DriverFactory,易导致线程隔离问题,改为从BaseTest传入已初始化的实例:
public class WrapperMethods { private DriverFactory driverFactory; private Page page; // 修改构造方法,接收外部的DriverFactory实例 public WrapperMethods(DriverFactory driverFactory) { this.driverFactory = driverFactory; } public void openApplication(String url) throws InterruptedException { page = driverFactory.getCurrentPage(); System.out.println(page.toString()); page.navigate(url); // 建议用Playwright内置等待替代Thread.sleep,提升稳定性 page.waitForLoadState(); } }
3. 在BaseTest中完成初始化与销毁逻辑
结合TestNG的注解,在测试前后执行浏览器初始化和资源销毁:
public class BaseTest { protected DriverFactory driverFactory; protected WrapperMethods wrapper; @BeforeMethod public void setup() { driverFactory = new DriverFactory(); driverFactory.initializeBrowser(); wrapper = new WrapperMethods(driverFactory); } @AfterMethod public void teardown() { driverFactory.destroy(); } }
4. 调整测试类
测试类直接复用BaseTest中初始化的WrapperMethods实例:
public class DesktopTest extends BaseTest { @Test public void navigateToWebPage() throws InterruptedException { wrapper.openApplication("https://www.youtube.com"); } }
额外建议
- 彻底移除
Thread.sleep(),改用Playwright提供的等待API(如page.waitForLoadState()、page.waitForSelector()),避免因等待时间不合理导致的不稳定问题。 - 将浏览器启动参数(如是否无头、浏览器通道)配置到properties文件中,实现配置与代码解耦。
内容的提问来源于stack exchange,提问作者Deepak_Mahalingam
相关产品推荐
相关产品推荐

