2

I am currently trying to achieve parallel test run with cucumber. I managed to run two different runners at the same time with the sure-fire plugin. Now I want to check whether is it possible to run SingleRunner file multiple times in parallel.

Ex: I have SignUpRunnerTest.java so I need to run this against few platforms parally.Is it possible?

This is my Runner file

import cucumber.api.CucumberOptions;
import cucumber.api.cli.Main;
import cucumber.api.junit.Cucumber;

import java.util.List;

import javax.management.MXBean;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"pretty", "html:target/html/", "json:target/cucumber.json", "junit:TEST-all.xml"},
        features = "src/test/java/resources/features/Search.feature", glue = {"com.browserstack.stepdefs"})
public class SignUpeRunnerTest {


}

Without Runner Approach

public class SignUpeRunnerTest {

    @Test
    public void test2() {
    Main.main(new String[]{"--threads", "4","-g", "com.browserstack.stepdefs", "src/test/java/resources/features/"});
    }

}

Factory Class

`import org.openqa.selenium.WebDriver;

public final class DriverFactory {

    private static ThreadLocal<WebDriver> drivers = new ThreadLocal();

    //To quit the drivers and browsers at the end only. 
    private static List<WebDriver> storedDrivers = new ArrayList();

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run(){
                storedDrivers.stream().forEach(WebDriver::quit);
            }
          });
    }

    private DriverFactory() {}

    public static WebDriver getDriver() {
        return drivers.get();
    }

    public static void addDriver(WebDriver driver) {
        storedDrivers.add(driver);
        drivers.set(driver);
    }

    public static void removeDriver() {
        storedDrivers.remove(drivers.get());
        drivers.remove();
    }   
}

`

Step Class

import org.openqa.selenium.By; import org.openqa.selenium.WebDriver;

public class SearchPage { private static WebDriver webDriver;

public SearchPage(WebDriver webDriver) {
    this.webDriver = webDriver;
    DriverFactory.addDriver(webDriver);
}

private By searchTermField = By.name("q");
private By submitSearch = By.id("_fZl");

public void enterSearchTerm(String searchTerm) {
    DriverFactory.getDriver().findElement(searchTermField).sendKeys(searchTerm);
}

public void submitSearch() {
    DriverFactory.getDriver().findElement(submitSearch).click();
}

}

This is my POM file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.browserstack</groupId>
    <artifactId>cucumber-jvm-java-browserstack</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>cucumber-jvm-java-browserstack</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cucumber.jvm.parallel.version>2.2.0</cucumber.jvm.parallel.version>
        <surefire.maven.plugin.version>2.19.1</surefire.maven.plugin.version>
        <acceptance.test.parallel.count>4</acceptance.test.parallel.count>
    </properties>

    <dependencies>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>4.2.3</version>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>4.2.3</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>datatable</artifactId>
            <version>1.1.12</version>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-testng</artifactId>
            <version>4.2.3</version>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-picocontainer</artifactId>
            <version>4.2.3</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.gfk.senbot/senbot-maven-plugin -->

  <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.0.1</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M3</version>
                <configuration>
                    <parallel>methods</parallel>
                    <threadCount>4</threadCount>
                    <reuserForks>false</reuserForks>
                    <testErrorIgnore>true</testErrorIgnore>
                    <testFailureIgnore>true</testFailureIgnore>
                    <includes>
                        <include>**/*RunnerTest.java</include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
Chinthaka Devinda
  • 997
  • 5
  • 16
  • 36
  • Glad if anyone can help.. thanks – Chinthaka Devinda Apr 19 '19 at 10:05
  • anyone? can help – Chinthaka Devinda Apr 19 '19 at 10:29
  • Copy and rename the existing runner class file as many times u need. Leave all the options as it is. Now u have multiple same runners with just different names. This then becomes the case that is already working for u. – Grasshopper Apr 19 '19 at 16:32
  • Also u should look at updating cucumber version. U r using very old ones. – Grasshopper Apr 19 '19 at 16:34
  • @Grasshopper, Thanks for the reply actually I do not want to repeat all the runner classes. Instead, I want to test one runner class across 10 different platforms in parallel. I actually achieved this using Junit and Selenium but it reuiqre my @Runwith(ParallelRunner.class) in the runner class but it is already occupied by ther cucumber runner class. I am stuck in there as well. – Chinthaka Devinda Apr 20 '19 at 03:55
  • Is this the ParallelRunner class u are using? https://michaeltamm.github.io/junit-toolbox/com/googlecode/junittoolbox/ParallelRunner.html – Grasshopper Apr 20 '19 at 04:54
  • @Grasshopper I am using this https://github.com/browserstack/junit-browserstack/blob/master/src/test/java/com/browserstack/Parallelized.java – Chinthaka Devinda Apr 20 '19 at 04:59
  • U can execute cucumber feature files without using any runner by using the main() method in class Main of package cucumber.api.cli. Refer to this [cli usage](https://github.com/cucumber/cucumber-jvm/blob/v4.0.0/core/src/main/resources/cucumber/api/cli/USAGE.txt) and [this article](http://grasshopper.tech/283/). Using this maybe it will work. Need some changes though. – Grasshopper Apr 20 '19 at 06:32
  • okay, in that case, can I still use @RunWith()? – Chinthaka Devinda Apr 20 '19 at 06:52
  • Sorry let me write it out as an answer. It needs some changes. Give me 5 mins. – Grasshopper Apr 20 '19 at 06:54
  • Sure @Grasshopper thanks – Chinthaka Devinda Apr 20 '19 at 06:55
  • Possible duplicate of [How to execute cucumber feature file parallel](https://stackoverflow.com/questions/41034116/how-to-execute-cucumber-feature-file-parallel) – Marit Jun 08 '19 at 11:17

3 Answers3

0

info.cukes dependency (are pretty old) which support cucumber till v 1.2.5 only and No more support for this after 12 September 2016

Other side, io.cucumber dependency supports Cucumber starting from v 2.0.x till latest v 4.3.x available as of now (Cucumber-JVM 4.0 gives you much flexibility for implementing parallel execution) and below are the steps to implement parallel execution using io.cucumber (Here you do not need to create individual runners per feature file & No need to use any old plug in like jvm-parallel plug in)

1.Adding correct set of dependency. I have followed JUnit during the implementation.

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>4.2.3</version>
</dependency>

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>4.2.3</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>datatable</artifactId>
    <version>1.1.12</version>
</dependency>


<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>4.2.3</version>
    <scope>test</scope>
</dependency>

2.Adding Maven-Surefire-Plugin under POM.XML

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M3</version>
    <configuration>
        <parallel>methods</parallel>
        <threadCount>1</threadCount>
        <reuserForks>false</reuserForks>
        <testErrorIgnore>true</testErrorIgnore>   
        <testFailureIgnore>true</testFailureIgnore>
        <includes>
            <include>**/*RunCukeTest.java</include>
        </includes>
    </configuration>
</plugin>
TheSociety
  • 1,936
  • 2
  • 8
  • 20
  • thank you for your response. I am looking to run single runner file multiple times in Pharrell. Coz my requirement is to run parallel devices same feature without creating runners repeatedly. – Chinthaka Devinda Apr 20 '19 at 04:44
  • Yes for this implementation, you would achieve parallel execution using single runner hence do not need to have multiple runners as it was required in info.cukes. – TheSociety Apr 20 '19 at 04:56
  • I have just tried it. Still launching a single thread. I used eclipse right click and run as junit as well as tried running pom file. Still same single Thread no multiple sessions created for me. – Chinthaka Devinda Apr 20 '19 at 06:07
  • Are you using TestNG under your framework ? because testNG dependency causes Surefire to ignore JUnit wrapper class. Remove all the TestNG dependencies or you can take a call to 2 define 2 execution - For TestNG & JUnit and disable one as per your need and I am using Maven Surefire Version 3.0.0-M3 – TheSociety Apr 20 '19 at 06:09
  • nope I do not use TestNG.it's only Junit + cucumber. Actually, I did an Rnd with Junit and selenium but it requires @RunWith annotation replaced but I cannot do that with cucumber runner class already used it. – Chinthaka Devinda Apr 20 '19 at 06:13
  • Can you please update runner class and dependencies in your post which you are using now. There shall be something missing. – TheSociety Apr 20 '19 at 06:14
  • Society I have just updated my runner file and .pom file – Chinthaka Devinda Apr 20 '19 at 06:25
  • Remove testNG dependency from pom and run it. – TheSociety Apr 20 '19 at 08:08
  • testNG dependency causes Surefire to ignore JUnit wrapper class. Remove all the TestNG dependencies or you can take a call to 2 define 2 execution - For TestNG & JUnit and disable one as per your need and I am using Maven Surefire Version 3.0.0-M3 – TheSociety Apr 20 '19 at 08:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/192138/discussion-between-chinthaka-devinda-and-thesociety). – Chinthaka Devinda Apr 20 '19 at 08:43
0

Cucumber feature files can be executed without using any runner by using the main() method in class Main of package cucumber.api.cli. Refer to this cli usage and this article. Using this maybe it will work. Need some changes though.

  1. Copy the code of BrowserStackJUnitTest into a new class rename it to something else say NewBSTest. This class will be used for running the test.

  2. Some change will be required in how the driver created for each thread will be accessed by selenium and cucumber code.

  3. Need to use a factory to store the drivers in a ThreadLocal variable in NewBSTest. U can refer to this class.

  4. In the NewBSTest class that u have created remove line no 30 - public WebDriver driver;. Change line 94 to add the created RemoteWebDriver to the ThreadLocal variable. SOmething like DriverFactory.addDriver(driver). Add DriverFactory.removeDriver() in method tearDown() line 98, maybe the first line. Change existing driver.quit(); to DriverFactory.getDriver().quit().

5.Remove the shutdown hook in the DriverFactory, BrowserStack will be quitting the actual driver anyways.

  1. Now in selenium or cucumber code u can access the driver using DriverFactory.getDriver(). This will impact your existing code pretty heavily.

  2. In the NewBSTest class add a test method like this. Hopefully this will work and the same features will be executed in each of the configured browserstack environments.

@Test
public void test() {
Main.main(new String[]{""-g", "stepdef", "src/test/resources/features/"});
}
Grasshopper
  • 8,908
  • 2
  • 17
  • 32
  • I have just tried it and it didn't work for me. I still see one single instance being launched from my runner class public void test() { Main.main(new String[]{"--threads", "4","-g", "com.browserstack.stepdefs", "src/test/java/resources/features/"}); } – Chinthaka Devinda Apr 20 '19 at 07:29
  • U do not need to use any runner now. This test method goes into the new class. Also remove threads option from the command. Can u add yhe new class code to the question. – Grasshopper Apr 20 '19 at 07:33
  • This rnd I did works as expected now I want to integrate the same with cucumber. But I can't use @Runwith if you have any idea on this that would be great https://drive.google.com/open?id=1Kuq1IW5fIqiSHdXXn-aLAAsaUCpTIwdy – Chinthaka Devinda Apr 20 '19 at 07:34
  • Not sure I understand ur requirement clearly. Hardly matters if u run using RunWith or main method. Also do not think u have implemented the above correctly or the code u uploaded is missing something. – Grasshopper Apr 20 '19 at 09:36
  • okay, may I know what's missing there? and Actually, my requirement is to run a single runner file parallelly (Ed: SignUpRunner (3 Features) so I need to run this SignUp runner in 3 devices in Parallel. Scenarios inside the runner can run sequentially but I need to launch the runner in parallel. – Chinthaka Devinda Apr 20 '19 at 09:47
0

You might have got answer for this question.To run testcases in parallel ,there are additional settings required as given below in the link- https://cucumber.io/docs/guides/parallel-execution/

According to this link if you are using surefire plugin, then package name should be parallel for the runner class.

For choosing the device type ,you can add tag for the feature file and further get the tag in before hook. I think for choosing the capability there might be better way available.Below logic is working for me-

@Before(order=2) public void LaunchBrowser(Scenario sc) { String browser= "firefox"; // ArrayList s = (ArrayList) sc.getSourceTagNames();

    //scenarios having this tag will be ignored and not run
    if(s.contains("@chrome"))
        browser = "chrome";
    else if(s.contains("@firefox"))
        browser = "firefox";

    driverfactory=new DriverFactory();
    driver=driverfactory.init_driver(browser);
    
}