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

PageFactory模式下多@Test执行异常,invalidSessionId及浏览器实例复用问题

问题分析与解决方案

核心问题原因

  1. 静态资源共享:BaseClass中的driver和wait被声明为static,属于类级变量,所有测试方法会共享同一个浏览器实例。第一个测试执行完closeBrowser()关闭会话后,后续测试复用已失效的driver就会触发invalidSessionId异常。
  2. 静态方法限制:initializeBrowser()和closeBrowser()为静态方法,只能操作静态变量,无法为每个测试实例创建独立的浏览器资源。
  3. 代码遗漏:BaseClass中EDGE分支缺少break,会默认执行default逻辑,可能导致浏览器初始化失败。
  4. 关闭方式不当:使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:31:00