Appium Cucumber Parallel Execution with TestNG [2021]

How to run Appium Tests in Parallel with Cucumber and TestNG? Yes, in this post, I will show you how we can achieve this! I will explain to you a mobile test automation project that contains TestNG, Appium, Cucumber. In this project, you can do your modifications to write your mobile test automation tests and run them in parallel. Before starting this article, I highly suggest you, check the below appium articles. I will extend Appium Parallel Testing architecture and add the cucumber support in this article.

Cucumber IntelliJ Plugins

In order to add Appium Cucumber support to our project in IntelliJ IDEA, we need to install “Gherkin” and “Cucumber for JAVA” plugins. You will download and then go to settings -> plugins and then install these plugins.

cucumber plugin settings on intellij

cucumber for java plugin

gherking plugin for intellij

Here, you can find also details: IntelliJ Cucumber Support

Cucumber Dependencies

After this step, you need to add the below Cucumber Dependencies to your pom.xml.

 <!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
 <dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-java</artifactId>
   <version>6.10.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-jvm -->
<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-jvm</artifactId>
   <version>6.10.3</version>
   <type>pom</type>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-core -->
<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-core</artifactId>
   <version>6.10.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/gherkin -->
<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>gherkin</artifactId>
   <version>18.1.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-testng</artifactId>
   <version>6.10.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-picocontainer</artifactId>
   <version>6.10.3</version>
   <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/net.masterthought/cucumber-reporting -->
<dependency>
   <groupId>net.masterthought</groupId>
   <artifactId>cucumber-reporting</artifactId>
   <version>5.5.3</version>
</dependency>

Cucumber Files and Folders

Then, I created a cucumber package and under this package, I created below packages and files:

appium cucumber parallel testing with testng

  • In the features package, we will hold all of our feature files.
  • In the steps package, we will write the steps of our features. BaseSteps file is a common/base file of all steps files.
  • In the tests package, we will have cucumber test classes.

I will explain the details of the above package and files. ;)

Appium Cucumber Parallel Test Automation with TestNG Scenario 

Our test scenario is a successful login of isinolsun application.

I will share some classes’ codes below but you can find the project code here: https://github.com/swtestacademy/appium-parallel-tests/tree/appium-cucumber-testng-parallel-testing

In the feature file, we should write our scenario in Gherkin syntax.

@Candidate
  Feature: Candidate can see the job's details.

    Scenario Outline: Candidate opens a job's page and see its details.
      Given Candidate is on the jobs listing screen
      When Candidate opens a job which has index of <index>
      Then Candidate should see the jobs details
      Examples: First and Second jobs
        | index |
        | 0     |
        | 1     |

BaseSteps file is the base class of all steps files. In this class, we declared all common variables and functions for all steps files.

package cucumber.steps;

import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import screens.CandidateMainScreen;
import screens.JobScreen;
import screens.SelectionScreen;
import screens.SplashScreen;

public class BaseSteps {
    protected SplashScreen        splashScreen;
    protected SelectionScreen     selectionScreen;
    protected CandidateMainScreen candidateMainScreen;
    protected JobScreen           jobScreen;

    public void setupScreens(AndroidDriver<MobileElement> driver) {
        splashScreen = new SplashScreen(driver);
        selectionScreen = new SelectionScreen(driver);
        candidateMainScreen = new CandidateMainScreen(driver);
        jobScreen = new JobScreen(driver);
    }
}

We need to write the detailed actions in the steps file. In JobsDetailsSteps file, I wrote all actions related to our steps.

package cucumber.steps;

import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import utilities.ThreadLocalDriver;

public class JobsDetailsSteps extends BaseSteps {

    @Before
    public void setupLoginSteps() {
        setupScreens(ThreadLocalDriver.getTLDriver());
    }

    @Given("Candidate is on the jobs listing screen")
    public void candidateIsOnTheJobsListingScreen() {
        splashScreen.skipSplashScreen();
        selectionScreen.clickIamSearchingJob();
        candidateMainScreen.allowNotification();
    }

    @When("Candidate opens a job which has index of {int}")
    public void candidateOpensTheIndexOfJobScreen(int index) {
        candidateMainScreen.clickToJob(index);
    }

    @Then("Candidate should see the jobs details")
    public void candidateShouldSeeTheJobsDetails() {
        jobScreen.assertToolBarTitleIsExpected();
    }
}

and now it is time to write our test runner file. In the below test file, we will run all features and generate cucumber reports. If you want, you can also modify this class to run specific cucumber features.

package cucumber.tests;

import io.cucumber.testng.CucumberOptions;
import io.cucumber.testng.FeatureWrapper;
import io.cucumber.testng.PickleWrapper;
import io.cucumber.testng.TestNGCucumberRunner;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

@CucumberOptions(
    monochrome = true,
    tags = "@Candidate",
    features = "src/test/java/cucumber/features",
    glue = "cucumber.steps",
    publish = true
)
public class TestRunner extends BaseTest {
    private TestNGCucumberRunner testNGCucumberRunner;

    @BeforeClass(alwaysRun = true)
    public void setUpClass() {
        testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
    }

    @Test(groups = "cucumber", description = "Run Cucumber Features.", dataProvider = "scenarios")
    public void scenario(PickleWrapper pickleWrapper, FeatureWrapper featureWrapper) {
        testNGCucumberRunner.runScenario(pickleWrapper.getPickle());
    }

    @DataProvider
    public Object[][] scenarios() {
        return testNGCucumberRunner.provideScenarios();
    }

    @AfterClass(alwaysRun = true)
    public void tearDownClass() {
        testNGCucumberRunner.finish();
    }
}

In BaseTest class, we do test setup and teardown operations.

package cucumber.tests;

import io.appium.java_client.android.AndroidDriver;
import java.io.IOException;
import java.net.URL;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import utilities.DesiredCapabilitiesUtil;
import utilities.ThreadLocalDriver;

public class BaseTest {
    private final DesiredCapabilitiesUtil desiredCapabilitiesUtil = new DesiredCapabilitiesUtil();

    @BeforeMethod
    @Parameters({ "udid", "platformVersion" })
    public void setup(String udid, String platformVersion) throws IOException {
        DesiredCapabilities caps = desiredCapabilitiesUtil.getDesiredCapabilities(udid, platformVersion);
        ThreadLocalDriver.setTLDriver(new AndroidDriver<>(new URL("http://127.0.0.1:4444/wd/hub"), caps));
    }

    @AfterMethod
    public synchronized void teardown() {
        ThreadLocalDriver.getTLDriver().quit();
    }
}

And we should change our TestNG XML file as shown below for parallel execution.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="IsinOlsun-Android-Test-Suite" parallel="tests" thread-count="2">

    <test name="emulator-5554">
        <parameter name="udid" value="emulator-5554"/>
        <parameter name="platformVersion" value="11"/>
        <classes>
            <class name="cucumber.tests.TestRunner"/>
        </classes>
    </test>

    <test name="emulator-5556">
        <parameter name="udid" value="emulator-5556"/>
        <parameter name="platformVersion" value="11"/>
        <classes>
            <class name="cucumber.tests.TestRunner"/>
        </classes>
    </test>
</suite>

When you run the TestNG.xml file, your mobile tests run in parallel. In this framework, you can both use Page Object Model and Cucumber together with TestNG. You can find the other files on the GitHub project page.

And you can go and see the reports after the test exection.

cucumber report on console

cucumber html report

Youtube Demo Video

Github Project

https://github.com/swtestacademy/appium-parallel-tests/tree/appium-cucumber-testng-parallel-testing

I hope you like this post. I would like to hear your feedback. Please share your comments with us.

Thanks.
Onur Baskirt

6 thoughts on “Appium Cucumber Parallel Execution with TestNG [2021]”

  1. Hi Onur,
    Such a great tutorial by u. I need your help regarding jira xray integration. Can u help me out by, i want to know how to integrate this with jira and execute it from jira.Plz help me.

    Reply
  2. Hi Onur,
    Thank you for the tutorial!
    I have one problem, my tests are not really running parallel… One phone just goes through a step and then after that one the next phone does the step..
    Do I have to work with threads or something? I’m a student and I have to work this out for a project, but I can’t really wrap my head around it….
    I would really appreciate your help… !

    Reply
    • Hi Milan, actually they were working very well. I also post its working video on youtube. However, selenium, appium, testNG always changing. Maybe in newer versions, there are some incompatibilities exist. Next week, I will be at work, I will check this. Please try to do below items and rerun your tests:
      1- Remove “synchronized” keyword at ThreadLocalDriver.java setTLDriver and getTLDriver methods.
      2- Try to get driver as follows in test classes
      Webdriver driver = ThreadLocalDriver.getTLDriver();
      Then instantiate screen classes with this local driver variable.

      Maybe these tricks will fix your problem.

      Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.