配置Cucumber-JVM后无法运行多浏览器并行测试,求解决方法
我来帮你搞定这个跨浏览器并行跑Cucumber Feature的问题!结合Cucumber-JVM和Selenium Grid的方案其实很清晰,咱们一步步调整配置,解决你的问题:
你现在继承了AbstractTestNGCucumberTests,这说明你是想用TestNG来驱动Cucumber测试,那并行运行的关键就在于TestNG的参数化+并行配置,再结合Selenium Grid的多浏览器节点。之前的Runner类缺少了参数化和并行的关键配置,所以没法实现多浏览器并行。
Selenium Grid是用来管理多浏览器测试节点的,先搞定它:
- 下载对应版本的Selenium Server Standalone包(要和你的Selenium Java客户端版本一致)
- 启动Grid Hub:
Hub默认在java -jar selenium-server-standalone-<版本号>.jar -role hubhttp://localhost:4444运行,你可以访问这个地址查看Grid状态。 - 启动不同浏览器的Node节点(每个开一个终端):
- Chrome节点:
java -Dwebdriver.chrome.driver="path/to/chromedriver" -jar selenium-server-standalone-<版本号>.jar -role node -hub http://localhost:4444/grid/register -browser browserName=chrome,maxInstances=3 - Firefox节点:
java -Dwebdriver.gecko.driver="path/to/geckodriver" -jar selenium-server-standalone-<版本号>.jar -role node -hub http://localhost:4444/grid/register -browser browserName=firefox,maxInstances=3
maxInstances是指这个节点最多同时跑多少个测试线程。 - Chrome节点:
把你的RunnerTest改成下面这样,用TestNG的@DataProvider提供浏览器参数,并重写Cucumber的场景方法来传递参数:
import io.cucumber.testng.AbstractTestNGCucumberTests; import io.cucumber.testng.CucumberOptions; import org.testng.annotations.DataProvider; @CucumberOptions( features = "src/test/resources/features", // 替换成你的Feature路径 glue = "com.yourpackage.stepdefinitions", // 替换成你的Step Definition包路径 monochrome = true, plugin = {"pretty", "html:target/cucumber-reports"} ) public class RunnerTest extends AbstractTestNGCucumberTests { // 提供多浏览器参数,这里可以扩展成更多浏览器(比如Edge) @DataProvider(parallel = true) @Override public Object[][] scenarios() { return new Object[][]{ {"chrome"}, {"firefox"} }; } }
这里的@DataProvider(parallel = true)是关键,它告诉TestNG要并行执行不同参数的测试。
在你的pom.xml里,把Surefire插件的配置改成这样,确保它能识别TestNG的并行配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.1.2</version> <!-- 用最新稳定版 --> <configuration> <parallel>tests</parallel> <threadCount>6</threadCount> <!-- 对应Grid节点的maxInstances总和,比如Chrome3+Firefox3=6 --> <systemPropertyVariables> <webdriver.chrome.driver>path/to/chromedriver</webdriver.chrome.driver> <webdriver.gecko.driver>path/to/geckodriver</webdriver.gecko.driver> </systemPropertyVariables> </configuration> </plugin>
如果想用更精细的控制,也可以创建TestNG的xml配置文件:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" > <suite name="Cucumber Parallel Suite" parallel="tests" thread-count="6"> <test name="Chrome Tests"> <parameter name="browser" value="chrome"/> <classes> <class name="com.yourpackage.RunnerTest"/> </classes> </test> <test name="Firefox Tests"> <parameter name="browser" value="firefox"/> <classes> <class name="com.yourpackage.RunnerTest"/> </classes> </test> </suite>
然后在Surefire配置里指定这个xml文件即可。
这里要注意线程安全,必须用ThreadLocal来管理Driver实例,避免不同线程的Driver互相干扰:
import io.cucumber.java.After; import io.cucumber.java.Before; import io.cucumber.java.ParameterType; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; public class Hooks { private static final ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>(); // 把DataProvider传过来的浏览器字符串转成DesiredCapabilities @ParameterType("chrome|firefox") public DesiredCapabilities browser(String browser) { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setBrowserName(browser); return capabilities; } // 在每个场景前初始化Driver,从Grid获取对应浏览器的实例 @Before public void setUp(DesiredCapabilities capabilities) throws Exception { WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capabilities); driverThreadLocal.set(driver); } // 提供获取Driver的方法,Step Definition里用这个获取当前线程的Driver public static WebDriver getDriver() { return driverThreadLocal.get(); } // 在每个场景后关闭Driver @After public void tearDown() { WebDriver driver = driverThreadLocal.get(); if (driver != null) { driver.quit(); driverThreadLocal.remove(); } } }
然后你的Step Definition里就可以通过Hooks.getDriver()来获取当前线程的WebDriver实例了。
- 版本匹配:Selenium Server、Selenium Java客户端、浏览器驱动(chromedriver/geckodriver)、浏览器版本必须匹配,否则会出现各种连接问题。
- Feature独立:要并行运行的Feature之间不能有依赖(比如共享测试数据、会话状态),否则会导致测试失败。
- 线程安全:所有测试相关的变量(比如Driver、测试数据)都要用ThreadLocal管理,避免线程冲突。
- Grid状态检查:启动Hub和Node后,一定要访问
http://localhost:4444/grid/console确认所有节点都正常注册了。
现在你可以执行mvn test,就能看到不同的Feature在Chrome和Firefox里并行运行啦!
内容的提问来源于stack exchange,提问作者user6618310

