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

TestNG并行执行测试时如何复用WebDriver驱动实例

TestNG并行测试复用浏览器驱动实现方案

核心逻辑是将驱动生命周期从测试方法级调整为工作线程级,通过ThreadLocal做线程隔离的驱动存储,驱动实例数和配置的thread-count数值完全一致,所有用例复用空闲线程绑定的已有驱动,无需反复启停。


第一步:实现线程绑定的驱动管理类

新建统一的驱动管理类,通过ThreadLocal为每个工作线程存储独立的驱动实例,线程首次获取驱动时才执行初始化,后续调用直接返回已有实例:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.time.Duration;

public class DriverManager {
    // 线程隔离存储驱动,每个工作线程对应一个独立驱动实例
    private static final ThreadLocal<WebDriver> DRIVER_THREAD_LOCAL = new ThreadLocal<>();
    // 替换为你实际的全局配置,和原有代码的配置对象保持一致即可
    private static String url = "你的测试系统地址";
    private static Properties prop;
    private static Date date;

    public static WebDriver getDriver() {
        // 当前线程未绑定驱动时才执行初始化,每个线程仅执行一次
        if (DRIVER_THREAD_LOCAL.get() == null) {
            // 替换为你实际的驱动创建逻辑,比如根据浏览器参数初始化Chrome/Firefox驱动
            WebDriver driver = new ChromeDriver();
            // 驱动基础配置
            driver.manage().window().maximize();
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
            driver.get(url);
            // 原有前置业务逻辑(登录、跳过改密提示)放在这里,每个驱动仅执行一次
            Demo_Page objDemoPage = new Demo_Page(driver, prop, date);
            objDemoPage.admin_demo("local");
            Home_page objHomePage = new Home_page(driver, prop, date);
            objHomePage.pwd_change_later();
            // 将初始化完成的驱动绑定到当前线程
            DRIVER_THREAD_LOCAL.set(driver);
        }
        return DRIVER_THREAD_LOCAL.get();
    }

    // 销毁当前线程绑定的驱动,供测试全部完成后调用
    public static void cleanDriver() {
        if (DRIVER_THREAD_LOCAL.get() != null) {
            DRIVER_THREAD_LOCAL.get().quit();
            DRIVER_THREAD_LOCAL.remove();
        }
    }
}

第二步:调整测试类注解逻辑

  • 删除原有@BeforeMethod中所有驱动初始化、前置登录相关代码,这部分逻辑已经移到驱动管理类的初始化流程中
  • 删除原有@AfterMethod中getDriver().quit()的驱动关闭逻辑,避免单个用例执行完销毁驱动
  • 测试类中所有获取驱动的逻辑,统一替换为调用DriverManager.getDriver(),不需要在单个测试类中单独维护ThreadLocal驱动存储

第三步:新增Suite级监听器处理最终驱动销毁

新建TestNG套件监听器,在全量用例执行完成后统一销毁所有线程绑定的驱动:

import org.testng.ISuite;
import org.testng.ISuiteListener;

public class SuiteDriverListener implements ISuiteListener {
    @Override
    public void onFinish(ISuite suite) {
        // 整个测试套件所有用例执行完成后,关闭当前线程绑定的驱动
        DriverManager.cleanDriver();
    }
}

第四步:调整testng.xml配置

  1. 将并行模式从parallel="tests"修改为parallel="methods",保证TestNG用固定大小的线程池(大小为thread-count配置值)调度所有测试方法
  2. 将新增的套件监听器加入监听器列表
    配置示例如下:
<suite name="Suite" parallel="methods" thread-count="2">
<listeners>
    <listener class-name="listeners3.Proj_Listener" />
    <listener class-name="你的实际类路径.SuiteDriverListener" />
</listeners>
    <!-- 原有<test>标签内容保持不变即可 -->
</suite>

注意事项

  • 可以保留@AfterMethod注解,但方法内仅能写用例状态重置逻辑,比如跳转回系统首页、清理当前用例生成的测试数据,避免上一个用例的操作上下文影响同线程下执行的下一个用例,示例代码:
@AfterMethod
public void resetTestStatus() {
    // 示例:用例执行完回到首页,保证下一个用例起始状态统一
    DriverManager.getDriver().get("你的系统首页地址");
}
  • 所有测试代码中禁止手动调用driver.quit(),驱动销毁逻辑统一交给套件监听器处理
  • 这套逻辑下启动的浏览器实例数和thread-count配置值完全一致,比如配置thread-count="2"就只会启动2个浏览器,所有用例排队复用这2个实例执行,不会出现每个用例启停浏览器的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:57:32