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

Selenium+TestNG多测试类按序执行失败,WebDriver共享异常求助

TestNG多测试类顺序执行时WebDriver实例及登录状态无法共享问题

问题描述

  • 需求:通过TestNG实现多测试类按顺序执行,先完成登录操作,再执行Onboarding相关测试
  • 异常情况:测试逻辑在单个文件时执行正常;拆分到Login_TestUser和Onboarding两个类后,登录类执行成功,但Onboarding类无法获取有效WebDriver实例及登录后的状态,测试失败
  • 疑问:不确定是testng.xml配置问题还是类间状态共享逻辑有误

相关代码

DriverManager类

public class DriverManager {
    private static WebDriver driver;

    public static WebDriver getDriver() {
        if (driver == null) {
            System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
            driver = new ChromeDriver();
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        }
        return driver;
    }

    public static void quitDriver() {
        if (driver != null) {
            driver.quit();
            driver = null;
        }
    }
}

ConfigurationFile类

public class ConfigurationFile {
    public static String getBaseUrl() {
        return "https://example.com";
    }

    public static String getUsername() {
        return "testuser";
    }

    public static String getPassword() {
        return "testpass";
    }
}

测试类:Login_TestUser

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;

public class Login_TestUser {
    private WebDriver driver;

    @BeforeClass
    public void setUp() {
        driver = DriverManager.getDriver();
        driver.get(ConfigurationFile.getBaseUrl());
        System.out.println("Login_TestUser driver instance: " + driver.hashCode());
    }

    @Test
    public void testLogin() {
        // 登录操作逻辑
        driver.findElement(By.id("username")).sendKeys(ConfigurationFile.getUsername());
        driver.findElement(By.id("password")).sendKeys(ConfigurationFile.getPassword());
        driver.findElement(By.id("login-btn")).click();
        // 验证登录成功
        assertTrue(driver.findElement(By.id("welcome-message")).isDisplayed());
    }

    @AfterClass
    public void tearDown() {
        // 错误示例:如果在这里quit driver,后续类会重新初始化实例
        // DriverManager.quitDriver();
    }
}

测试类:Onboarding

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;

public class Onboarding {
    private WebDriver driver;

    @BeforeClass
    public void setUp() {
        driver = DriverManager.getDriver();
        System.out.println("Onboarding driver instance: " + driver.hashCode());
    }

    @Test
    public void testOnboardingStep1() {
        // Onboarding操作逻辑
        driver.findElement(By.id("next-btn")).click();
        assertTrue(driver.findElement(By.id("step2")).isDisplayed());
    }
}

testng.xml配置

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="TestSuite" verbose="1">
    <test name="LoginAndOnboarding">
        <classes>
            <class name="com.example.Login_TestUser"/>
            <class name="com.example.Onboarding"/>
        </classes>
    </test>
</suite>

控制台日志示例

[TestNG] Running:
  /path/to/testng.xml

Starting ChromeDriver 114.0.5735.90 (...) on port 9515
Only local connections are allowed.
...
Login_TestUser driver instance: 123456
PASSED: testLogin
...
Starting ChromeDriver 114.0.5735.90 (...) on port 9516
Only local connections are allowed.
...
Onboarding driver instance: 789012
FAILED: testOnboardingStep1
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"id","selector":"next-btn"}
...

解决方案

1. 修复WebDriver实例的生命周期管理

问题核心:如果Login_TestUser的@AfterClass中调用了DriverManager.quitDriver(),会销毁WebDriver实例,导致Onboarding类重新初始化新浏览器,丢失登录状态。

修复步骤:

  • 移除测试类@AfterClass中的quitDriver()调用
  • 创建套件级别的销毁逻辑,确保所有测试完成后再关闭浏览器:
    import org.testng.annotations.AfterSuite;
    
    public class SuiteSetup {
        @AfterSuite
        public void tearDownSuite() {
            DriverManager.quitDriver();
        }
    }
    
  • 在testng.xml中添加该类,保证套件结束时执行销毁:
    <suite name="TestSuite" verbose="1">
        <test name="LoginAndOnboarding">
            <classes>
                <class name="com.example.SuiteSetup"/>
                <class name="com.example.Login_TestUser"/>
                <class name="com.example.Onboarding"/>
            </classes>
        </test>
    </suite>
    

2. 确保测试类执行顺序严格性

TestNG默认按<classes>标签内的顺序执行,但可以添加preserve-order="true"强制保证顺序:

<test name="LoginAndOnboarding" preserve-order="true">
    <classes>
        <class name="com.example.Login_TestUser"/>
        <class name="com.example.Onboarding"/>
    </classes>
</test>

3. 验证实例一致性

在两个测试类的setUp方法中打印driver的哈希值,如果输出不同,说明DriverManager的单例逻辑存在问题,检查是否有多线程干扰或实例被意外重置。

4. 避免测试类独立生命周期影响

TestNG每个测试类的@BeforeClass/@AfterClass独立执行,必须保证整个测试套件共用同一个WebDriver实例,直到所有测试完成再销毁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 12:13:09