PageFactory模式下多@Test执行异常,invalidSessionId及浏览器实例复用问题
问题分析与解决方案
核心问题原因
- 静态资源共享:
BaseClass中的driver和wait被声明为static,属于类级变量,所有测试方法会共享同一个浏览器实例。第一个测试执行完closeBrowser()关闭会话后,后续测试复用已失效的driver就会触发invalidSessionId异常。 - 静态方法限制:
initializeBrowser()和closeBrowser()为静态方法,只能操作静态变量,无法为每个测试实例创建独立的浏览器资源。 - 代码遗漏:
BaseClass中EDGE分支缺少break,会默认执行default逻辑,可能导致浏览器初始化失败。 - 关闭方式不当:使用
driver.close()仅关闭当前窗口,无法彻底终止浏览器会话,容易残留无效驱动进程。
修改后的代码示例
1. 重构BaseClass(移除静态修饰,优化资源管理)
public class BaseClass { private static Properties prop; protected WebDriver driver; // 改为实例变量,每个测试实例独立拥有 protected WebDriverWait wait; @BeforeSuite public void propReading() { try { File file = new File(ConstantPaths.PROP_PATH); FileInputStream fileInputStream = new FileInputStream(file); prop = new Properties(); prop.load(fileInputStream); } catch (IOException e) { System.err.println("Properties文件未找到: " + e.getMessage()); } } // 改为非静态方法,操作当前实例的driver public void initializeBrowser() { String browserName = prop.getProperty("browserName").toUpperCase(); switch (browserName) { case "CHROME": driver = new ChromeDriver(); ChromeOptions options = new ChromeOptions(); // options.addArguments("kiosk-printing"); break; case "FIREFOX": driver = new FirefoxDriver(); break; case "EDGE": driver = new EdgeDriver(); break; // 补充break,避免执行default逻辑 default: System.err.println("不支持的浏览器名称: " + browserName); throw new IllegalArgumentException("非法浏览器类型"); } driver.manage().window().maximize(); driver.get(prop.getProperty("urlName")); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); } // 改为非静态方法,确保彻底终止会话 public void closeBrowser() { if (driver != null) { driver.quit(); // 替代close(),彻底关闭浏览器会话 driver = null; // 置空避免后续无效引用 } } }
2. 调整测试类VerifyLoginTest(确保每个测试实例独立初始化)
package testscripts; import actions.Actions; import base.BaseClass; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import pagesobjects.HomePage; public class VerifyLoginTest extends BaseClass{ @BeforeMethod public void startBrowser() { initializeBrowser(); // 直接调用实例方法,无需类名前缀 } @Test public void verifyNoValue(){ // 为当前测试实例的driver创建HomePage对象(替换单例模式) HomePage homePage = new HomePage(driver); homePage.enterInvestmentAmount(" "); homePage.clickOnCalculate(); Assert.assertEquals(homePage.getErrorMsg(),"This field is required"); Actions.takeScreenshot(driver, "verifyNoValue"); // 确保截图方法接收当前driver } @Test public void verifyMinValue(){ HomePage homePage = new HomePage(driver); homePage.enterInvestmentAmount("499"); homePage.clickOnCalculate(); Assert.assertEquals(homePage.getErrorMsg(),"Min Amount is 500"); Actions.takeScreenshot(driver, "verifyMinValue"); } @Test public void verifyMaxValue(){ HomePage homePage = new HomePage(driver); homePage.enterInvestmentAmount("50000001"); homePage.clickOnCalculate(); // 修正断言错误信息(原代码错误使用Min提示) Assert.assertEquals(homePage.getErrorMsg(),"Max Amount is 50000000"); Actions.takeScreenshot(driver, "verifyMaxValue"); } @AfterMethod public void tearDown(){ closeBrowser(); // 调用实例方法关闭当前浏览器 } }
3. 补充HomePage调整(避免单例共享driver)
确保HomePage通过构造器接收driver,而非单例模式:
public class HomePage { private WebDriver driver; // 构造器注入当前测试实例的driver public HomePage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } // 页面元素操作方法... }
关键优化点说明
- 实例化资源:每个测试方法对应一个
VerifyLoginTest实例,拥有独立的driver,实现测试间完全隔离。 - 会话彻底终止:使用
driver.quit()替代close(),确保浏览器进程完全退出,避免残留无效会话。 - 修复分支逻辑:补充
EDGE分支的break,避免非法浏览器提示错误触发。 - 页面对象绑定:
HomePage通过构造器接收当前driver,确保每个页面实例与对应浏览器绑定。
内容的提问来源于stack exchange,提问作者Palash Soni
相关产品推荐
相关产品推荐

