您正在WebDriver
跨多个线程共享一个实例。因此,一个测试可以WebDriver
在另一个测试afterMethod
已经退出它(因此会话未找到异常)或尚未加载 google.com(因此没有此类元素异常)之后尝试使用。
如果您想使用 TestNG 并行运行 Selenium WebDriver 测试,那么您可以使用 aThreadLocal
来维护WebDriver
每个线程的实例。
例如
public class DemoTest {
private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = new InheritableThreadLocal<>();
@Test(dataProvider = "dp")
public void f(Integer n, String s) {
WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
System.out.println("Driver: " + driver.toString());
driver.get("www.google.com");
driver.findElement(By.id("lst-ib")).sendKeys("1234567");
System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
}
@BeforeMethod
public void beforeMethod() {
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();
WEB_DRIVER_THREAD_LOCAL.set(driver);
System.out.println("Before method id:" + Thread.currentThread().getId());
}
@AfterMethod
public void afterMethod() {
WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
System.out.println("After method id:" + Thread.currentThread().getId());
if (driver != null) {
driver.quit();
}
}
@DataProvider(parallel = true)
public Object[][] dp() {
return new Object[][]{
new Object[]{1, "a"},
new Object[]{2, "b"},
new Object[]{3, "c"},
new Object[]{4, "d"},
};
}
}
我省略了用 try-catch 块包装每个测试,因为 TestNG 已经捕获了测试/配置方法抛出的异常并为它们打印堆栈跟踪等。
上面的示例将为每个测试创建一个WebDriver
与测试线程关联的实例。即,如果它们真正并行运行,您将打开 4 个 Firefox 实例(我认为这是您想要的)。
如果您有比线程更多的测试并且想要重用WebDriver
实例,那么您可以使用具有初始值的 ThreadLocal。
例如
public class DemoTest {
private static final Set<WebDriver> WEB_DRIVERS = new HashSet<>();
private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = InheritableThreadLocal
.withInitial(new Supplier<WebDriver>() {
@Override
public WebDriver get() {
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().window().maximize();
WEB_DRIVERS.add(driver);
System.out.println("Before thread id:" + Thread.currentThread().getId());
return driver;
}
});
@Test(dataProvider = "dp")
public void f(Integer n, String s) {
WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
System.out.println("Driver: " + driver.toString());
driver.get("www.google.com");
driver.findElement(By.id("lst-ib")).sendKeys("1234567");
System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
}
@AfterClass
public void afterClass() {
for (WebDriver webDriver : WEB_DRIVERS) {
try {
webDriver.quit();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@DataProvider(parallel = true)
public Object[][] dp() {
return new Object[][]{
new Object[]{1, "a"},
new Object[]{2, "b"},
new Object[]{3, "c"},
new Object[]{4, "d"},
};
}
}
还有一个 testng.xml 来减少线程总数来证明这一点:
<suite name="Suite" parallel="methods" thread-count="2" data-provider-thread-count="2">
<test name="prelogin">
<classes>
<class name="DemoTest"/>
</classes>
</test>
</suite>
示例输出(看看它如何只创建 2 个 FirefoxDriver 实例,并行运行两个测试,然后并行运行接下来的两个测试,使用所有可用线程并为每个线程重用 Web 驱动程序):
Before thread id:14
Driver: FirefoxDriver: firefox on WINDOWS (e924b5f1-9ace-46e5-a6b3-d1494de7e94d)
method f id:14 n:2 s:b
Before thread id:13
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:1 s:a
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:3 s:c
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:4 s:d