I have below feature files (Separate feature files) in src/test/resources/feature/ and I would like to run them in parallel. Like: One feature file has to execute in chrome and another one has to execute in firefox as mentioned #Tags name.
Feature: Refund item
#chrome
Scenario: Jeff returns a faulty microwave
Given Jeff has bought a microwave for $100
And he has a receipt
When he returns the microwave
Then Jeff should be refunded $100
Feature: Refund Money
#firefox
Scenario: Jeff returns the money
Given Jeff has bought a microwave for $100
And he has a receipt
When he returns the microwave
Then Jeff should be refunded $100
Can somebody assist me to achieve this.I'm using cucumber-java 1.2.2 version, and AbstractTestNGCucumberTests using as runner. Also, let me know how can I create a Test Runner dynamically by using feature files and make them run in parallel.
Update: 4.0.0 version is available at maven central repository with bunch of changes.for more details go here.
Update: 2.2.0 version is available at maven central repository.
You can use opensource plugin 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>
First you need to add this plugin with required configuration in your project pom file.
<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>
Now add below plugin just below above plugin which will invoke runner classes generated by above plugin
<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>
Above two plugins will do magic for cucumber test running in parallel (provided you machine also have advanced hardware support).
Strictly provided <forkCount>n</forkCount> here 'n' is directly proportional to 1) Advanced Hardware support and 2) you available nodes i.e. registered browser instances to HUB.
One major and most important changes is your WebDriver class must be SHARED and you should not implement driver.quit() method, as closing is take care by shutdown hook.
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());
}
}
}
Considering you want to execute more than 50 threads i.e. same no of browser instances are registered to HUB but Hub will die if it doesn't get enough memory therefore to avoid this critical situation you should start hub with -DPOOL_MAX=512 (or larger) as stated in 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
Cucumber does not support parallel execution out of the box.
I've tried, but it is not friendly.
We have to use maven's capability to invoke it in parallel. Refer link
Also there is a github project which uses custom plugin to execute in parallel.
Refer cucumber-jvm-parallel-plugin
If all you are expecting is to be able to run multiple features in parallel, then you can try doing the following :
Duplicate the class AbstractTestNGCucumberTests in your test project and set the attribute parallel=true to the #DataProvider annotated method.
Since the default dataprovider-thread-count from TestNG is 10 and now that you have instructed TestNG to run features in parallel, you should start seeing your feature files get executed in parallel.
But I understand that Cucumber reporting is inherently not thread safe, so your reports may appear garbled.
I achieved cucumber parallelism using courgette-jvm . It worked out of the box and run parallel test at scenario level
Simply inlclude similar runner class in cucumber. My tests are further using RemoteWebdriver to open multiple instances on selenium grid. Make sure grid is up and running and node is registered to the grid.
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 config is
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();
}
To take maximum advantage of TestNG you can use Testng's third party extension QAF framework. It supports multiple bdd syntax including gherkin using GherkinFactory.
While using BDD with QAF, you can take advantage of each TestNG features, including data-providers, parallel execution configuration in different ways (groups/tests/methods), TestNG listeners.
QAF considers each scenario as TestNG test and Scenario Outline as TestNG data-driven test. As qaf provides driver management and resource management in-built, you don't need to write single line of code for driver management or resource management. All you need to do is create TestNG xml configuration file as per your requirement either to run parallel methods (scenarios) or groups or xml test on one or more browser.
It enables different possible configuration combinations. Below is the xml configuration to address this question which will run scenarios in two browsers and in parallel. You can configure number of threads for each browser as standard TestNG xml configuration as well.
<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>
More over the latest BDDTestFactory2 supports 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 to provide test data in XML/JSON/CSV/EXCEL/DB using meta-data in BDD.
EDIT:
Cucumber-5 users can take benefit of qaf-cucumber support library.
Since v4 of Cucumber you can do this without extensions of plugins.
https://github.com/cucumber/cucumber-jvm/tree/main/cucumber-testng#parallel-execution
Cucumber TestNG supports parallel execution of scenarios. Override the
scenarios method to enable parallel execution.
public class RunCucumberTest extends
AbstractTestNGCucumberTests {
#Override
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
}
Maven Surefire plugin configuration for parallel execution
<plugins> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<property>
<name>dataproviderthreadcount</name>
<value>${threadcount}</value>
</property>
</properties>
</configuration>
</plugin>
</plugins>
Where dataproviderthreadcount is the default number of threads to use
for data providers when running tests in parallel.
The #Nested classes that are executed in JUnit 5 they are ordered to run AFTER all the tests in eclosing class. How could I enforce the same behavior using maven, if my goal is to run a single enclosing class and it's nested classes? Is there a commandline or pom.xml modification to make this example test pass?
package example;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
public class SomeTopLevelTest {
private static boolean nestedDone = false;
#Test
void test1() {
Assertions.assertFalse(nestedDone,
"Nested classes should execute after the enclosing tests");
}
#Nested
class SomeNestedTest {
#Test
void test2() {
nestedDone = true;
}
}
#AfterAll
static void recheck() {
Assertions.assertTrue(nestedDone, "Nested class should be executed");
}
}
This does pass in IDE:
But does not in commanline, if I try to specify the name:
mvn test -Dtest=example.SomeTopLevelTest
[ERROR] Failures:
[ERROR] SomeTopLevelTest.recheck:27 Nested class should be executed ==> expected: <true> but was: <false>
mvn test -Dtest=example.SomeTopLevelTest*
[ERROR] Failures:
[ERROR] SomeTopLevelTest.test1:14 Nested classes should execute after the enclosing tests ==> expected: <false> but was: <true>
The problem of #Nested classes not executing is a known issue and it has been reported in both JUnit5 and Surefire issue trackers, but as of now remains unresolved.
The current state of affairs (tested with Maven 3.6.3, Junit5 5.7.2, Surefire 2.22.2 up to 3.0.0-M5):
A. Not selecting a test
mvn test
Results in executing all test classes as expected: methods from enclosing classes first, and then methods from #Nested classes, level by level
B. Selecting test the standard way
mvn test -Dtest=example.SomeTopLevelTest
This apparently triggers the default surefire excludes that use the following pattern:
<excludes>
<exclude>**/*$*</exclude>
</excludes>
Why does it not happen in case A is a mystery, but one can override this behaviour by explicitly clearing the excludes pattern:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude/>
</excludes>
</configuration>
</plugin>
It does not seem to be possible to do without modyfing the pom.xml.
This DOES NOT solve the issue as posted in this question, because the nested classes are still executed first.
C. Using wildcard with -Dtest parameter
mvn test -Dtest=example.SomeTopLevelTest*
This explicitly selects all the nested classes, but - as stated in the question - results in executing the nested classes first, so it's not a solution.
D. Using includes
mvn test -DtestName=example.SomeTopLevelTest
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>${testName}</include>
</includes>
</configuration>
</plugin>
Apparently include patterns work quite differently than -Dtest parameter, because this is finally the solution to pass the test from the question. With this setup the testName may be a single class, wildcard pattern or regex
example.SomeTopLevelTest to execute all test methods in single class
example/* - all tests (including nested) in package example, but not sub-packages
example/** - all tests in package and subpackages
advanced regex, is supprted too
I'm trying to reconfigure my test results to not show skip results for configuration methods & is skews my data.
I'm running tests through TestNG where each method has a #beforeMethod and #afterMethod configuration method. In the beforeMethod I check whether a #Test method should run or not & if not I throw a SkipException to skip it.
In my current situation I have 2 test methods I run. One is made to fail and the other is designed to be skipped. So I expect to get a result of 1 fail and 1 skip. In the IDE console this is the result I get, but when I run it through Maven I get 1 fail and 3 skips. Here is my emailable-result.html. The failed test case has no #beforeMethod or #afterMethod showing.
I found out about the IConfigurationListener but I am not sure how to use it to remove a configuration method from the report. I am also using maven surefire
This is what I have so far.
public class MyConfigurationListenerAdapter implements IConfigurationListener {
#Override
public void onConfigurationSkip(ITestResult itr) {
String configName = itr.getName();
if (configName.equals("beforeMethod")||configName.equals("afterMethod")){
//TODO remove itr from test result
}
}
}
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>java_accelerator.testng.classes.MyConfigurationListenerAdapter</value>
</property>
</properties>
<!-- Suite testng xml file to consider for test execution -->
<suiteXmlFiles>
<suiteXmlFile>src/test/java/testclasses/tests/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
Anyone able to help me from here?
One of our classes uses a system property to load a configuration file. In a particular test case, we set this property to an invalid value to check the behavior of the class under test (CUT) in this situation.
The same class is also used transitively in various integration tests. Since we are using JUnit Jupiter's parallel test execution capabilities, we are witnessing race conditions in those integration tests that are using the CUT under the hood. They are failing because the system property is sometimes still invalid.
The parallelism itself is configured globally via the Maven Surefire plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<properties>
<configurationParameters>
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.dynamic.factor=1
</configurationParameters>
</properties>
</configuration>
</plugin>
Consequently, all tests run in parallel per default. The CUT looks like this:
class AttributesProviderTest {
#Test
#ResourceLock( value = SYSTEM_PROPERTIES, mode = READ_WRITE )
void invalid_attributes_file_should_yield_UncheckedIOException() throws Exception {
final Properties backup = new Properties();
backup.putAll( System.getProperties() );
final String attributesFile = "foo";
System.setProperty( AttributesProvider.ATTRIBUTES_FILE_PROPERTY, attributesFile );
assertThatThrownBy( AttributesProvider::getTestInstance )
.isExactlyInstanceOf( UncheckedIOException.class )
.hasMessage( "Cannot read attributes file '" + attributesFile + "'." );
System.setProperties( backup );
}
// Some other tests...
}
As it can be seen, we are trying to synchronize the system property access. However, if I have understood correctly, this only works for other #ResourceLock-annotated tests, and does not magically synchronize system property access in general?
Is there a way to fix the race condition (without annotating all other tests)? Some ideas:
Ensure the CUT is executed sequentially at the beginning (or some other sort of synchronization).
Refactor the CUT and invoke corresponding file-reading method with a parameter directly.
Throw away the test case.
I run my JUnit and Mockito tests in a big project. I use them for testing my server-side components that connect to web-service. All these connections require some time and it is not neccessary for them to be executed during the build.
I would like that my tests would be ignored during the build.
I have about 10 classes with tests. So the obvious way is to annotate all the classes with #Ignore. However I should do this every time I commit my code to the project and then re-annotate all tests. Not the very best solution I think.
So is this possible somehow simply ignore all package (let say com.example.tests) with the tests?
Or what might be the solution to ignore tests in the build in a simple way?
You can mention on your build.gradle what packages to exclude from tests
test {
exclude '**/*IntegrationTest*'
}
same for maven:
must consider this notation:
By default, the Surefire Plugin will automatically include all test classes with the following wildcard patterns:
"**/Test*.java" - includes all of its subdirectories and all Java filenames that start with "Test".
"**/*Test.java" - includes all of its subdirectories and all Java filenames that end with "Test".
"**/*Tests.java" - includes all of its subdirectories and all Java filenames that end with "Tests".
"**/*TestCase.java" - includes all of its subdirectories and all Java filenames that end with "TestCase".
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<excludes>
<exclude>*com.example.tests*/*Test.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
Another option is the old
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
or even when call it
mvn install -DskipTests
Using Categories seems to be an option that can come in handy
This is how you may add these to your Gradle script.
test {
useJUnit {
includeCategories 'org.gradle.junit.CategoryA'
excludeCategories 'org.gradle.junit.CategoryB'
}
}
A sample can be found here, adding it for a quick reference.
public interface FastTests
{
/* category marker */
}
public interface SlowTests
{
/* category marker */
}
public class A
{
#Category(SlowTests.class)
#Test public void a()
{
}
}
#Category(FastTests.class})
public class B
{
#Test public void b()
{
}
}
#RunWith(Categories.class)
#IncludeCategory(SlowTests.class)
#ExcludeCategory(FastTests.class)
#SuiteClasses({ A.class, B.class })
public class SlowTestSuite
{
}
I have found the solution for my case.
To disable all the tests during the build or even in any other context that you want the Spring annotation #IfProfileValue can be used. All tests with this annotation will be executed only in wanted context.
The example is this:
#IfProfileValue(name="enableTests", value="true")
public class DemoApplicationTests {
#Test
public void contextLoads() {
...
}
}
In my IDE I can edit the configuration and set the variable by:
-DenableTests=true
This annotation can be used on the level of a class or on the level of a test also.
All classes or tests annotated with such #IfProfileValue will be executed only in my environment and will be ignored during the build.
This approach is the best for me because it is not convenient in my project to change main pom.xml for my own test needs.
Addition.
Also in Spring or Spring Boot you should add Runner.
For example in Spring:
#RunWith(SpringJUnit4ClassRunner.class)
#IfProfileValue(name="enableTests", value="true")
#ContextConfiguration(classes = { YourClassConfig.class })
YourClassConfig might be empty:
#Configuration
public class YourClassConfig {
}