如何并行执行黄瓜功能文件
How to execute cucumber feature file parallel
我在 src/test/resources/feature/ 中有以下功能文件(单独的功能文件),我想 运行 它们并行。喜欢:一个功能文件必须在 chrome 中执行,另一个功能文件必须在 firefox 中执行,如@Tags 名称所述。
Feature: Refund item
@chrome
Scenario: Jeff returns a faulty microwave
Given Jeff has bought a microwave for 0
And he has a receipt
When he returns the microwave
Then Jeff should be refunded 0
Feature: Refund Money
@firefox
Scenario: Jeff returns the money
Given Jeff has bought a microwave for 0
And he has a receipt
When he returns the microwave
Then Jeff should be refunded 0
有人可以帮助我实现 this.I' 使用 cucumber-java 1.2.2 版本,以及使用 运行ner 的 AbstractTestNGCucumberTests。另外,让我知道如何使用功能文件动态创建测试运行器并使它们并行 运行。
Cucumber 不支持开箱即用的并行执行。
我试过了,但是不友好
- 我们必须使用maven 的能力来并行调用它。参考 link
- 还有一个 github 项目使用自定义插件并行执行。
参考 cucumber-jvm-parallel-plugin
如果您只希望能够并行 运行 多项功能,那么您可以尝试执行以下操作:
- 在您的测试项目中复制 class AbstractTestNGCucumberTests 并将属性
parallel=true
设置为 @DataProvider
注释方法。
由于 TestNG 的默认 dataprovider-thread-count
是 10
,现在您已指示 TestNG 并行 运行 features
,您应该开始看到您的功能文件得到并行执行。
但我知道 Cucumber 报告本质上不是线程安全的,因此您的报告可能会出现乱码。
更新: 4.0.0 版本可在 Maven 中央存储库中获得,并进行了一系列更改。for more details go here.
更新: 2.2.0 版本可在 maven 中央存储库获得。
您可以使用开源插件cucumber-jvm-parallel-plugin which has many advantages over existing solutions. Available at maven repository
<dependency>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>2.1.0</version>
</dependency>
首先,您需要在您的项目 pom 文件中添加具有所需配置的插件。
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<!-- Mandatory -->
<!-- comma separated list of package names to scan for glue code -->
<glue>foo, bar</glue>
<outputDirectory>${project.build.directory}/generated-test-sources/cucumber</outputDirectory>
<!-- The directory, which must be in the root of the runtime classpath, containing your feature files. -->
<featuresDirectory>src/test/resources/features/</featuresDirectory>
<!-- Directory where the cucumber report files shall be written -->
<cucumberOutputDir>target/cucumber-parallel</cucumberOutputDir>
<!-- comma separated list of output formats json,html,rerun.txt -->
<format>json</format>
<!-- CucumberOptions.strict property -->
<strict>true</strict>
<!-- CucumberOptions.monochrome property -->
<monochrome>true</monochrome>
<!-- The tags to run, maps to CucumberOptions.tags property you can pass ANDed tags like "@tag1","@tag2" and ORed tags like "@tag1,@tag2,@tag3" -->
<tags></tags>
<!-- If set to true, only feature files containing the required tags shall be generated. -->
<filterFeaturesByTags>false</filterFeaturesByTags>
<!-- Generate TestNG runners instead of default JUnit ones. -->
<useTestNG>false</useTestNG>
<!-- The naming scheme to use for the generated test classes. One of 'simple' or 'feature-title' -->
<namingScheme>simple</namingScheme>
<!-- The class naming pattern to use. Only required/used if naming scheme is 'pattern'.-->
<namingPattern>Parallel{c}IT</namingPattern>
<!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per scenario. FEATURE generates a runner per feature. -->
<parallelScheme>SCENARIO</parallelScheme>
<!-- This is optional, required only if you want to specify a custom template for the generated sources (this is a relative path) -->
<customVmTemplate>src/test/resources/cucumber-custom-runner.vm</customVmTemplate>
</configuration>
</execution>
</executions>
</plugin>
现在在上面的插件下面添加下面的插件,它将调用上面的插件classes 生成的运行器
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<forkCount>5</forkCount>
<reuseForks>true</reuseForks>
<includes>
<include>**/*IT.class</include>
</includes>
</configuration>
</plugin>
以上两个插件可以同时对 cucumber 测试 运行 施展魔法(前提是你的机器也有高级硬件支持)。
此处严格提供 <forkCount>n</forkCount>
'n' 与 1) 高级硬件支持和 2) 可用节点(即向 HUB 注册的浏览器实例)成正比。
一个主要且最重要的变化是您的 WebDriver class 必须 SHARED 而您应该 而不是 实施 driver.quit() 方法,因为关闭是由关闭钩子处理的。
import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
public class SharedDriver extends EventFiringWebDriver {
private static WebDriver REAL_DRIVER = null;
private static final Thread CLOSE_THREAD = new Thread() {
@Override
public void run() {
REAL_DRIVER.close();
}
};
static {
Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
}
public SharedDriver() {
super(CreateDriver());
}
public static WebDriver CreateDriver() {
WebDriver webDriver;
if (REAL_DRIVER == null)
webDriver = new FirefoxDriver();
setWebDriver(webDriver);
return webDriver;
}
public static void setWebDriver(WebDriver webDriver) {
this.REAL_DRIVER = webDriver;
}
public static WebDriver getWebDriver() {
return this.REAL_DRIVER;
}
@Override
public void close() {
if (Thread.currentThread() != CLOSE_THREAD) {
throw new UnsupportedOperationException("You shouldn't close this WebDriver. It's shared and will close when the JVM exits.");
}
super.close();
}
@Before
public void deleteAllCookies() {
manage().deleteAllCookies();
}
@After
public void embedScreenshot(Scenario scenario) {
try {
byte[] screenshot = getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
} catch (WebDriverException somePlatformsDontSupportScreenshots) {
System.err.println(somePlatformsDontSupportScreenshots.getMessage());
}
}
}
考虑到你想执行超过 50 个线程,即同样没有浏览器实例注册到 HUB,但是如果 Hub 没有足够的内存就会死掉,因此为了避免这种危急情况,你应该开始-DPOOL_MAX=512(或更大)的集线器,如 grid2 documentation.
中所述
Really large (>50 node) Hub installations may need to increase the jetty threads by setting -DPOOL_MAX=512 (or larger) on the java command line.
java -jar selenium-server-standalone-<version>.jar -role hub -DPOOL_MAX=512
要最大限度地利用 TestNG,您可以使用 Testng 的第三方扩展 QAF framework. It supports multiple bdd syntax including gherkin using GherkinFactory。
在将 BDD 与 QAF 结合使用时,您可以利用每个 TestNG 功能,包括数据提供程序、不同方式的并行执行配置 (groups/tests/methods)、TestNG 侦听器。
QAF 将每个场景视为 TestNG 测试,将场景大纲视为 TestNG 数据驱动测试。由于qaf内置了驱动管理和资源管理,你不需要为驱动管理和资源管理写一行代码。您需要做的就是根据您的要求创建 TestNG xml 配置文件 运行 并行方法(场景)或组或 xml 在一个或多个浏览器上进行测试。
它实现了不同的可能configuration combinations。下面是 xml 解决这个问题的配置 这将 运行 在两个浏览器中并行的场景。您也可以为每个浏览器配置线程数作为标准 TestNG xml 配置。
<suite name="AUT Test Automation" verbose="0" parallel="tests">
<test name="Test-on-chrome">
<parameter name="scenario.file.loc" value="resources/features" />
<parameter name="driver.name" value="chromeDriver" />
<classes>
<class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
</classes>
</test>
<test name="Test-on-FF">
<parameter name="scenario.file.loc" value="resources/features" />
<parameter name="driver.name" value="firefoxDriver" />
<classes>
<class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
</classes>
</test>
</suite>
更多最新的 BDDTestFactory2
支持 syntax that is derived from QAF BDD, Jbehave and gherkin. It supports meta-data from qaf bdd as tags and examples from gherkin. You can take benefit of inbuilt data-providers 使用 BDD 中的元数据在 XML/JSON/CSV/EXCEL/DB 中提供测试数据。
编辑:
Cucumber-5 用户可以利用 qaf-cucumber 支持库。
我使用 courgette-jvm
实现了黄瓜并行性。它开箱即用,运行 场景级别的并行测试
只需在黄瓜中包含类似的 运行ner class。我的测试进一步使用 RemoteWebdriver
在 selenium 网格上打开多个实例。确保网格已启动并且 运行ning 并且节点已注册到网格。
import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.CucumberOptions;
import courgette.api.testng.TestNGCourgette;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@Test
@CourgetteOptions(
threads = 10,
runLevel = CourgetteRunLevel.SCENARIO,
rerunFailedScenarios = true,
rerunAttempts = 1,
showTestOutput = true,
reportTitle = "Courgette-JVM Example",
reportTargetDir = "build",
environmentInfo = "browser=chrome; git_branch=master",
cucumberOptions = @CucumberOptions(
features = "src/test/resources/com/test/",
glue = "com.test.stepdefs",
publish = true,
plugin = {
"pretty",
"json:target/cucumber-report/cucumber.json",
"html:target/cucumber-report/cucumber.html"}
))
class AcceptanceIT extends TestNGCourgette {
}
RemoteWebdriver 配置为
protected RemoteWebDriver createDriver() throws MalformedURLException , IOException {
Properties properties = new Properties();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String hubURL = "http://192.168.1.7:65299/wd/hub";
System.setProperty("webdriver.gecko.driver", "/Users/amit/Desktop/amit/projects/misc/geckodriver");
FirefoxProfile profile = new FirefoxProfile();
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability(FirefoxDriver.PROFILE, profile);
capabilities.setPlatform(Platform.ANY);
FirefoxOptions options = new FirefoxOptions();
options.merge(capabilities);
driver.set(new RemoteWebDriver(new URL(hubURL),options));
return driver.get();
}
我在 src/test/resources/feature/ 中有以下功能文件(单独的功能文件),我想 运行 它们并行。喜欢:一个功能文件必须在 chrome 中执行,另一个功能文件必须在 firefox 中执行,如@Tags 名称所述。
Feature: Refund item
@chrome
Scenario: Jeff returns a faulty microwave
Given Jeff has bought a microwave for 0
And he has a receipt
When he returns the microwave
Then Jeff should be refunded 0
Feature: Refund Money
@firefox
Scenario: Jeff returns the money
Given Jeff has bought a microwave for 0
And he has a receipt
When he returns the microwave
Then Jeff should be refunded 0
有人可以帮助我实现 this.I' 使用 cucumber-java 1.2.2 版本,以及使用 运行ner 的 AbstractTestNGCucumberTests。另外,让我知道如何使用功能文件动态创建测试运行器并使它们并行 运行。
Cucumber 不支持开箱即用的并行执行。 我试过了,但是不友好
- 我们必须使用maven 的能力来并行调用它。参考 link
- 还有一个 github 项目使用自定义插件并行执行。 参考 cucumber-jvm-parallel-plugin
如果您只希望能够并行 运行 多项功能,那么您可以尝试执行以下操作:
- 在您的测试项目中复制 class AbstractTestNGCucumberTests 并将属性
parallel=true
设置为@DataProvider
注释方法。
由于 TestNG 的默认 dataprovider-thread-count
是 10
,现在您已指示 TestNG 并行 运行 features
,您应该开始看到您的功能文件得到并行执行。
但我知道 Cucumber 报告本质上不是线程安全的,因此您的报告可能会出现乱码。
更新: 4.0.0 版本可在 Maven 中央存储库中获得,并进行了一系列更改。for more details go here.
更新: 2.2.0 版本可在 maven 中央存储库获得。
您可以使用开源插件cucumber-jvm-parallel-plugin which has many advantages over existing solutions. Available at maven repository
<dependency>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>2.1.0</version>
</dependency>
首先,您需要在您的项目 pom 文件中添加具有所需配置的插件。
<plugin> <groupId>com.github.temyers</groupId> <artifactId>cucumber-jvm-parallel-plugin</artifactId> <version>2.1.0</version> <executions> <execution> <id>generateRunners</id> <phase>generate-test-sources</phase> <goals> <goal>generateRunners</goal> </goals> <configuration> <!-- Mandatory --> <!-- comma separated list of package names to scan for glue code --> <glue>foo, bar</glue> <outputDirectory>${project.build.directory}/generated-test-sources/cucumber</outputDirectory> <!-- The directory, which must be in the root of the runtime classpath, containing your feature files. --> <featuresDirectory>src/test/resources/features/</featuresDirectory> <!-- Directory where the cucumber report files shall be written --> <cucumberOutputDir>target/cucumber-parallel</cucumberOutputDir> <!-- comma separated list of output formats json,html,rerun.txt --> <format>json</format> <!-- CucumberOptions.strict property --> <strict>true</strict> <!-- CucumberOptions.monochrome property --> <monochrome>true</monochrome> <!-- The tags to run, maps to CucumberOptions.tags property you can pass ANDed tags like "@tag1","@tag2" and ORed tags like "@tag1,@tag2,@tag3" --> <tags></tags> <!-- If set to true, only feature files containing the required tags shall be generated. --> <filterFeaturesByTags>false</filterFeaturesByTags> <!-- Generate TestNG runners instead of default JUnit ones. --> <useTestNG>false</useTestNG> <!-- The naming scheme to use for the generated test classes. One of 'simple' or 'feature-title' --> <namingScheme>simple</namingScheme> <!-- The class naming pattern to use. Only required/used if naming scheme is 'pattern'.--> <namingPattern>Parallel{c}IT</namingPattern> <!-- One of [SCENARIO, FEATURE]. SCENARIO generates one runner per scenario. FEATURE generates a runner per feature. --> <parallelScheme>SCENARIO</parallelScheme> <!-- This is optional, required only if you want to specify a custom template for the generated sources (this is a relative path) --> <customVmTemplate>src/test/resources/cucumber-custom-runner.vm</customVmTemplate> </configuration> </execution> </executions> </plugin>
现在在上面的插件下面添加下面的插件,它将调用上面的插件classes 生成的运行器
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <forkCount>5</forkCount> <reuseForks>true</reuseForks> <includes> <include>**/*IT.class</include> </includes> </configuration> </plugin>
以上两个插件可以同时对 cucumber 测试 运行 施展魔法(前提是你的机器也有高级硬件支持)。
此处严格提供
<forkCount>n</forkCount>
'n' 与 1) 高级硬件支持和 2) 可用节点(即向 HUB 注册的浏览器实例)成正比。一个主要且最重要的变化是您的 WebDriver class 必须 SHARED 而您应该 而不是 实施 driver.quit() 方法,因为关闭是由关闭钩子处理的。
import cucumber.api.Scenario; import cucumber.api.java.After; import cucumber.api.java.Before; import org.openqa.selenium.OutputType; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.support.events.EventFiringWebDriver; public class SharedDriver extends EventFiringWebDriver { private static WebDriver REAL_DRIVER = null; private static final Thread CLOSE_THREAD = new Thread() { @Override public void run() { REAL_DRIVER.close(); } }; static { Runtime.getRuntime().addShutdownHook(CLOSE_THREAD); } public SharedDriver() { super(CreateDriver()); } public static WebDriver CreateDriver() { WebDriver webDriver; if (REAL_DRIVER == null) webDriver = new FirefoxDriver(); setWebDriver(webDriver); return webDriver; } public static void setWebDriver(WebDriver webDriver) { this.REAL_DRIVER = webDriver; } public static WebDriver getWebDriver() { return this.REAL_DRIVER; } @Override public void close() { if (Thread.currentThread() != CLOSE_THREAD) { throw new UnsupportedOperationException("You shouldn't close this WebDriver. It's shared and will close when the JVM exits."); } super.close(); } @Before public void deleteAllCookies() { manage().deleteAllCookies(); } @After public void embedScreenshot(Scenario scenario) { try { byte[] screenshot = getScreenshotAs(OutputType.BYTES); scenario.embed(screenshot, "image/png"); } catch (WebDriverException somePlatformsDontSupportScreenshots) { System.err.println(somePlatformsDontSupportScreenshots.getMessage()); } } }
考虑到你想执行超过 50 个线程,即同样没有浏览器实例注册到 HUB,但是如果 Hub 没有足够的内存就会死掉,因此为了避免这种危急情况,你应该开始-DPOOL_MAX=512(或更大)的集线器,如 grid2 documentation.
中所述Really large (>50 node) Hub installations may need to increase the jetty threads by setting -DPOOL_MAX=512 (or larger) on the java command line.
java -jar selenium-server-standalone-<version>.jar -role hub -DPOOL_MAX=512
要最大限度地利用 TestNG,您可以使用 Testng 的第三方扩展 QAF framework. It supports multiple bdd syntax including gherkin using GherkinFactory。 在将 BDD 与 QAF 结合使用时,您可以利用每个 TestNG 功能,包括数据提供程序、不同方式的并行执行配置 (groups/tests/methods)、TestNG 侦听器。
QAF 将每个场景视为 TestNG 测试,将场景大纲视为 TestNG 数据驱动测试。由于qaf内置了驱动管理和资源管理,你不需要为驱动管理和资源管理写一行代码。您需要做的就是根据您的要求创建 TestNG xml 配置文件 运行 并行方法(场景)或组或 xml 在一个或多个浏览器上进行测试。
它实现了不同的可能configuration combinations。下面是 xml 解决这个问题的配置 这将 运行 在两个浏览器中并行的场景。您也可以为每个浏览器配置线程数作为标准 TestNG xml 配置。
<suite name="AUT Test Automation" verbose="0" parallel="tests">
<test name="Test-on-chrome">
<parameter name="scenario.file.loc" value="resources/features" />
<parameter name="driver.name" value="chromeDriver" />
<classes>
<class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
</classes>
</test>
<test name="Test-on-FF">
<parameter name="scenario.file.loc" value="resources/features" />
<parameter name="driver.name" value="firefoxDriver" />
<classes>
<class name="com.qmetry.qaf.automation.step.client.gherkin.GherkinScenarioFactory" />
</classes>
</test>
</suite>
更多最新的 BDDTestFactory2
支持 syntax that is derived from QAF BDD, Jbehave and gherkin. It supports meta-data from qaf bdd as tags and examples from gherkin. You can take benefit of inbuilt data-providers 使用 BDD 中的元数据在 XML/JSON/CSV/EXCEL/DB 中提供测试数据。
编辑: Cucumber-5 用户可以利用 qaf-cucumber 支持库。
我使用 courgette-jvm
实现了黄瓜并行性。它开箱即用,运行 场景级别的并行测试
只需在黄瓜中包含类似的 运行ner class。我的测试进一步使用 RemoteWebdriver
在 selenium 网格上打开多个实例。确保网格已启动并且 运行ning 并且节点已注册到网格。
import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.CucumberOptions;
import courgette.api.testng.TestNGCourgette;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@Test
@CourgetteOptions(
threads = 10,
runLevel = CourgetteRunLevel.SCENARIO,
rerunFailedScenarios = true,
rerunAttempts = 1,
showTestOutput = true,
reportTitle = "Courgette-JVM Example",
reportTargetDir = "build",
environmentInfo = "browser=chrome; git_branch=master",
cucumberOptions = @CucumberOptions(
features = "src/test/resources/com/test/",
glue = "com.test.stepdefs",
publish = true,
plugin = {
"pretty",
"json:target/cucumber-report/cucumber.json",
"html:target/cucumber-report/cucumber.html"}
))
class AcceptanceIT extends TestNGCourgette {
}
RemoteWebdriver 配置为
protected RemoteWebDriver createDriver() throws MalformedURLException , IOException {
Properties properties = new Properties();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String hubURL = "http://192.168.1.7:65299/wd/hub";
System.setProperty("webdriver.gecko.driver", "/Users/amit/Desktop/amit/projects/misc/geckodriver");
FirefoxProfile profile = new FirefoxProfile();
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability(FirefoxDriver.PROFILE, profile);
capabilities.setPlatform(Platform.ANY);
FirefoxOptions options = new FirefoxOptions();
options.merge(capabilities);
driver.set(new RemoteWebDriver(new URL(hubURL),options));
return driver.get();
}