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

如何解决Data Provider并行执行时仅单个浏览器接收输入数据的错误?

问题:TestNG Data Provider并行执行时仅单个浏览器获取数据

我尝试通过Data Provider实现并行执行,但两个浏览器打开后,输入数据仅传入其中一个浏览器。

原代码

package PracticePrograms;

import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class DataProviderSample1{
    
    public WebDriver driver;
    
    @BeforeMethod
    public void setUp() throws InterruptedException {

        WebDriverManager.firefoxdriver().setup();
        driver = new FirefoxDriver();       
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));   
        driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");

    }
    
    @Test(dataProvider = "inputData")
    public void testLogin(String UserName, String Password ) throws InterruptedException {
    
        driver.findElement(By.name("username")).sendKeys(UserName);
        driver.findElement(By.name("password")).sendKeys(Password);
        driver.findElement(By.xpath("//button[@type='submit']")).click();
    }
    
    @DataProvider(name = "inputData", parallel = true)
    public static Object[][] loginData() {
        Object[][] data = new Object[2][2];
        data[0][0] = "Admin";
        data[0][1] = "admin123";

        data[1][0] = "admin";
        data[1][1] = "admin123";

        return data;
    }
    
     @AfterMethod
        public void tear_down() throws InterruptedException {
           driver.quit();            
        }  

}

问题原因

核心问题是WebDriver实例的线程共享冲突:

  • 并行执行时,TestNG会启动多个线程运行@Test方法
  • 你的driver是类的实例变量,多个线程会同时修改这个变量的引用,最终所有线程都会指向最后创建的那个WebDriver实例,导致只有这个实例能获取到输入数据

解决方案

使用ThreadLocal<WebDriver>为每个线程单独存储WebDriver实例,确保每个测试线程拥有独立的浏览器会话。

修改后的代码

package PracticePrograms;

import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import io.github.bonigarcia.wdm.WebDriverManager;

public class DataProviderSample1{
    
    // 用ThreadLocal实现线程隔离,每个线程拥有独立的WebDriver实例
    private ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>();
    
    @BeforeMethod
    public void setUp() throws InterruptedException {
        WebDriverManager.firefoxdriver().setup();
        WebDriver driver = new FirefoxDriver();       
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));   
        driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        
        // 将当前线程的driver存入ThreadLocal
        driverThreadLocal.set(driver);
    }
    
    @Test(dataProvider = "inputData")
    public void testLogin(String UserName, String Password ) throws InterruptedException {
        // 获取当前线程对应的driver实例
        WebDriver driver = driverThreadLocal.get();
        
        driver.findElement(By.name("username")).sendKeys(UserName);
        driver.findElement(By.name("password")).sendKeys(Password);
        driver.findElement(By.xpath("//button[@type='submit']")).click();
    }
    
    @DataProvider(name = "inputData", parallel = true)
    public static Object[][] loginData() {
        Object[][] data = new Object[2][2];
        data[0][0] = "Admin";
        data[0][1] = "admin123";

        data[1][0] = "admin";
        data[1][1] = "admin123";

        return data;
    }
    
    @AfterMethod
    public void tear_down() throws InterruptedException {
        // 关闭当前线程的driver并清理ThreadLocal引用
        WebDriver driver = driverThreadLocal.get();
        if (driver != null) {
            driver.quit();
            driverThreadLocal.remove();
        }
    }  
}

关键修改说明

  1. 替换实例变量为ThreadLocal<WebDriver>,实现线程级别的实例隔离
  2. @BeforeMethod中创建driver后,存入当前线程的ThreadLocal存储区
  3. @Test方法中通过get()获取当前线程专属的driver实例
  4. @AfterMethod中关闭driver后,调用remove()清理ThreadLocal引用,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:50:44