如何解决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(); } } }
关键修改说明
- 替换实例变量为
ThreadLocal<WebDriver>,实现线程级别的实例隔离 @BeforeMethod中创建driver后,存入当前线程的ThreadLocal存储区@Test方法中通过get()获取当前线程专属的driver实例@AfterMethod中关闭driver后,调用remove()清理ThreadLocal引用,避免内存泄漏
内容的提问来源于stack exchange,提问作者k chary
相关产品推荐
相关产品推荐

