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

TestNG+Cucumber+Appium并行测试PageFactory初始化报错问题

问题现象

基于TestNG+Cucumber+Appium搭建并行执行测试框架时,第二个运行线程抛出org.openqa.selenium.NoSuchSessionException: Session ID is null异常:

  • 使用BaseMobile中Method1的静态方法初始化PageObject时稳定复现报错
  • 改用构造函数初始化(Method2)时用例可正常运行
根因定位

三个核心问题导致并行场景下报错:

  • 静态Driver破坏ThreadLocal线程隔离
    BaseMobile中定义的protected static AppiumDriver driver = new AndroidDeviceA().getDriver();是类级别的静态变量,在类第一次加载时就会执行初始化:此时测试线程还未执行@BeforeClass中的driver初始化逻辑,ThreadLocal中存储的driver为null;同时静态变量被所有线程共享,并行执行时后启动的线程会覆盖该变量值,先启动的线程会拿到其他线程已quit的driver实例,直接触发无会话异常。
  • PageFactory初始化方式不符合Appium要求
    Method1直接调用PageFactory.initElements(driver, clazz)传入静态driver,没有使用Appium提供的AppiumFieldDecorator做装饰,无法正确识别Appium的移动端元素注解(如@AndroidFindBy),元素代理绑定的driver实例本身就是错误的。
  • Driver初始化判空逻辑无效
    AndroidDeviceA.initializeDriver()方法中新建了局部变量AppiumDriver driver = null;做判空,永远不会命中ThreadLocal中已存储的当前线程driver,虽然不是本次报错的直接原因,但并行场景下存在重复初始化driver的风险。
修复方案
  • 删除BaseMobile中的静态driver变量,所有driver实例统一从AndroidDeviceA的ThreadLocal中获取,保证线程隔离
  • 修正静态Page初始化方法,使用AppiumFieldDecorator绑定当前线程的实时driver实例,和Method2的初始化逻辑对齐
  • 修正driver初始化的判空逻辑,直接判断当前线程ThreadLocal中存储的driver是否存在,避免重复初始化

修正后的核心代码:

BaseMobile修正后代码

public class BaseMobile {
    TestUtils utils = new TestUtils();
    public final static Logger logger = LogManager.getLogger();

    // 实时获取当前线程绑定的driver,禁止用静态变量存储driver
    protected AppiumDriver getDriver() {
        return new AndroidDeviceA().getDriver();
    }

    // 修正后的Method1,对齐Method2的初始化逻辑
    public static <T extends BaseMobile> T instanceOf(Class<T> clazz) {
        return PageFactory.initElements(
                new AppiumFieldDecorator(new AndroidDeviceA().getDriver()),
                clazz
        );
    }
}

AndroidDeviceA初始化逻辑修正

public void initializeDriver() throws Exception {
    // 直接判断当前线程绑定的driver,不要定义局部变量做无效判空
    if (driver.get() == null) {
        try {
            utils.log().info("initializing Appium driver");
            AppiumDriver driverInstance = new AndroidDriver(new AppiumServer().getServer().getUrl(), new UiAutomatorOptions().getUiAutomatorOptionsMobile());

            if (driverInstance == null) {
                throw new Exception("driver is null. ABORT!!!");
            }
            utils.log().info("Driver is initialized");
            utils.log().info("session"+ driverInstance.getSessionId());
            driver.set(driverInstance);
        } catch (IOException e) {
            e.printStackTrace();
            utils.log().fatal("Driver initialization failure. ABORT !!!!" + e.toString());
            throw e;
        }
    }
}
Method2正常运行的原因

Method2在实例化Page对象时才执行初始化:

  • 此时@BeforeClass逻辑已经执行完成,当前线程的driver已经完成初始化并存入ThreadLocal,能拿到正确的会话实例
  • 初始化时使用了AppiumFieldDecorator装饰driver,元素代理绑定的是当前线程的正确driver,不会出现跨线程会话错乱的问题

内容的提问来源于stack exchange,提问作者jordan99

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:03:57