[英]TestNG Selenium with parallel threads
I've seen many questions regarding this topic but none seem to pertain to what I am looking for. 我已经看到许多有关此主题的问题,但似乎都与我所寻找的问题无关。 I am trying to run parallel methods under a single class using the @BeforeMethod
to start up the browser, and @AfterMethod
to tear down the browser. 我试图使用@BeforeMethod
启动浏览器,并使用@AfterMethod
拆除浏览器,在单个类下运行并行方法。 For this example, let's just say it is a single class file that had several test methods inside of it. 对于此示例,我们只说它是一个单个类文件,其中包含多个测试方法。 I wish to run 4 of them at the same time in different browsers. 我希望在不同的浏览器中同时运行其中的4个。 We are using Groovy but a Java answer would suffice. 我们正在使用Groovy,但是Java答案就足够了。
XML: XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="sampleSuite" thread-count="4" preserve-order="true" parallel="methods">
<test name="sample">
<classes>
<class name="tests.some.class.MyClassFile"/>
</classes>
</test>
</suite>
DriverFactory class that is in charge of simply creating and returning a browser: 负责简单地创建和返回浏览器的DriverFactory类:
private static WebDriver createWebDriver() {
String property = System.getProperty("driver", "chrome")
def capabilities
if (property == "chrome") {
capabilities = DesiredCapabilities.chrome()
} else if (property == "firefox") {
System.setProperty("webdriver.gecko.driver", "/usr/local/Cellar/geckodriver/0.16.1/bin/geckodriver")
capabilities = DesiredCapabilities.firefox()
}
def url = System.getProperty("seleniumServerUrl", "http://localhost:4444/wd/hub")
if (!url) {
throw new IllegalStateException("No 'seleniumServerUrl' system property set")
}
def webDriver = new RemoteWebDriver(new URL(url), capabilities)
webDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS)
webDriver.manage().window().setSize(new Dimension(1920,1080))
Runtime.addShutdownHook {
try {
webDriver.quit()
} catch (ignore) {}
}
webDriver
}
For threading, also in DriverFactory class: 对于线程化,同样在DriverFactory类中:
static final WebDriver createStackWebDriver(){
ThreadLocal<WebDriver> webDriver = new ThreadLocal<WebDriver>(){
protected WebDriver initialValue(){
createWebDriver()
}
}
webDriver.get()
}
Now I have a TestPlatform class that is the central "set up and tear down" piece of the architecture. 现在,我有一个TestPlatform类,它是体系结构的中心“设置和拆除”部分。 All of my class files that contain the @Test
methods extends this TestPlatform class: 我所有包含@Test
方法的类文件都扩展了此TestPlatform类:
class TestPlatform {
WebDriver webDriver
@BeforeMethod
void startUpWebBrowser(){
webDriver = DriverFactory.createStackWebDriver()
}
@AfterMethod
void quitWebDriver(){
webDriver.quit()
}
}
When we run the XML file, what we see is 4 instances of startUpWebBrowser()
, one out of the 4 would "pass" and continue the test, and it will promptly open up 4 methods out of one instance of startUpWebBrowser()
, while the other 3 just stay "hanging". 当我们运行XML文件时,我们看到的是startUpWebBrowser()
4个实例,这4个实例中的1个将“通过”并继续测试,它将立即从startUpWebBrowser()
的一个实例中打开4个方法,而其他3个保持“挂起”状态。 We need it to open up one browser in each startUpWebBrowser()
instance, instead of 4 browsers in one instance. 我们需要它在每个startUpWebBrowser()
实例中打开一个浏览器,而不是在一个实例中打开4个浏览器。
Our current workaround is to wrap EACH @Test
method inside its own class, and change the @BeforeMethod
into @BeforeClass
as well as the afters. 我们当前的解决方法是将EACH @Test
方法包装在其自己的类中,并将@BeforeMethod
更改为@BeforeClass
以及afters。 This somehow works but is extremely ugly on the reporting side of it, and there are other few drawbacks to this way. 这在某种程度上是可行的,但是在报告方面却非常丑陋,而且这种方式还有其他一些缺点。
Is there any solution to this issue without doing an overhaul of the current architecture? 如果不对当前体系结构进行彻底检查,是否可以解决此问题? Am I just missing something very simple? 我只是想念一些简单的东西吗?
The problem lies in your Test class TestPlatform
wherein you are saving a webdriver instance variable into a class level data member WebDriver webDriver
. 问题出在您的Test类TestPlatform
其中您将一个webdriver实例变量保存到一个类级别的数据成员WebDriver webDriver
。
So when two or more @Test
methods run in parallel, all of them are literally trying to assign the webdriver instance to the same webDriver
instance. 因此,当两个或多个@Test
方法并行运行时,所有这些方法实际上都是在尝试将webdriver实例分配给相同的webDriver
实例。
Please fix it as below. 请按照以下说明进行修复。
class TestPlatform {
@BeforeMethod
void startUpWebBrowser(){
DriverFactory.createStackWebDriver()
//Access webdriver instances only via DriverFactory.createStackWebDriver()
}
@AfterMethod
void quitWebDriver(){
DriverFactory.createStackWebDriver().quit()
}
}
Seems like a ThreadLocal
misusing. 似乎是ThreadLocal
滥用。 I'd use the following snippet: 我将使用以下代码段:
private static final ThreadLocal<WebDriver> DRIVER_CONTAINER = new ThreadLocal<>();
@BeforeMethod
void startUpWebBrowser(){
DRIVER_CONTAINER.set(createWebDriver());
}
@AfterMethod
void quitWebDriver(){
ofNullable(getDriver()).ifPresent(WebDriver::quit);
DRIVER_CONTAINER.remove();
}
public static WebDriver getDriver() {
return DRIVER_CONTAINER.get();
}
Or just move driver management piece into IInvokedMethodListener
. 或者只是将驱动程序管理块移到IInvokedMethodListener
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.