Quantcast
Channel: Pochampalli IT Labs
Viewing all articles
Browse latest Browse all 261

Cucumber scenarios parallel execution with ThreadLocal | TestNG, Java Selenium, Maven , POM page factory

$
0
0

 Hi, In this post, we will see how to run cucumber scenarios in parallel with TestNG. 

For the demonstration purposes, I kept the project structure simple, one package for all classes and a folder for scenarios. 
Below is how it looks like in Eclipse. 

Video tutorial: 
Watch the no voice demo at : https://youtu.be/IkrXOkkDG5c

                 

Codebase: 
View at GitHub  or Download Zip

Software setup : 

  • java version "1.8.0_371" 

Java(TM) SE Runtime Environment (build 1.8.0_371-b11)

Java HotSpot(TM) 64-Bit Server VM (build 25.371-b11, mixed mode)


What is this demonstration intended to  ? 
Execute two scenarios in parallel from a single feature file. 
i.e.,
1) Verify user is able to login to the application with valid credentials 
2) Verify Forgot password link is displayed on login page. 

Concepts : 
  1. Dependencies/plugins in pom.xml
  2. Basic DriverFactory for chrome driver with ThreadLocal 
  3. POM model with page factory pattern. 
  4. Parallel execution configurations 
  5. Cucumber hooks 
  6. Is it necessary to have testng.xml for parallel execution if the code run from eclipse ? 
You could download the source code of this demo using below links: 
1) GitHub
2) Google Drive 

You could also walk through the no voice video tutorial of the same demo at 

What google says about thread local  ? 
ThreadLocal is a special class in Java that helps us achieve thread safety by providing per-thread 
contexts and maintaining them separately for each thread. 
In other words, ThreadLocal is a Java class that can be used to define variables accessible solely 
by the thread that created them.

Deep dive into thread local look at these. 
Officical
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ThreadLocal.html
From Java Point: 
https://www.javatpoint.com/java-threadlocal-class


Here we go! 
  • Add all aforementioned dependencies/plugins in pom.xml file. In the maven-surefire-plugin configure parallel test with methods and number of threads to open when run automation.  


  • Define the DriverFactory class with ThreadLocal web driver and then set the driver, get the driver, quit the driver with ThreadLocal class methods. This is the major aspect of localizing thread for step definitions. 

    privatestatic ThreadLocal<WebDriver> driver = new ThreadLocal<>();

  • Create cucumber runner class, in this write the piece of parallel testing. Making true enables the parallel testing and false to normal/sequential tests.  

    @Override

    @DataProvider(parallel = true)

    public Object[][] scenarios() {

    returnsuper.scenarios();

    }

  • It is always an automation best practice to keep the tests independent of one another, especially my experience with cucumber is to use Before and After hooks efficiently to trigger the browser instance and quit it when completes. I vote cucumber hooks over TestNG hooks with cucumber integration with TestNG.

    @Before(order=0)

    publicvoid before(Scenario scenaio) throws Exception{

    DriverFactory.setDriver();

    System.out.println("Current Thread Name:"+Thread.currentThread().getName());

    System.out.println("Current Thread ID:"+Thread.currentThread().getId());

    }

    @After(order=0)

    publicvoid after() throws Exception{

    DriverFactory.closeDriver();

    }

  • Login to the application , Forgot Password resides on same Login page, so single feature is good enough to have this for Gherkin 

    Login.feature

    #Author: Sadakar Pochampalli

    @LoginFeature

    Feature: Login page validations


    Background:

    Given User is on login page


    @Login

    Scenario: Login to Orange HRM

    When User enters username "Admin"

    And User enters password "Admin123"

    And User clicks on Login button

    Then User should navigate to Orange HRM home page


    @ForgotPassword

    Scenario: Forgot password link verification

    Then User verifies Forgot password link display

  • Now, it's the Page Object Model with page factory pattern. (Refer bottom section for complete code) 

    LoginPageFactory.java

    public WebDriver driver;


    public LoginPageFactory(WebDriver driver) {

    this.driver = driver;

    }


    // Username locator

    @FindBy(xpath = "//input[@name='username']")

    public WebElement userName;


  • Initialize the elements in the step definition. (Refer bottom section for complete code) 

    LoginStepDef.java

    LoginPageFactory login = PageFactory.initElements(DriverFactory.getDriver(), LoginPageFactory.class);

    @Given("User is on login page")

    publicvoid user_is_on_login_page() throws InterruptedException {

    DriverFactory.getDriver().get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");

    Thread.sleep(3000);

    }


    @When("User enters username {string}")

    publicvoid user_enters_username(String username) {

    login.enterUsername(username);

    }


That's all for the parallel testing - update the maven project and run as TestNG, you would see two threads/browsers are opened of a single instance and performs testing operations. 

Complete code: 
pom.xml
<projectxmlns="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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>CucumberParallelExecutionTestNG</groupId><artifactId>CucumberParallelExecutionTestNG</artifactId><version>0.0.1-SNAPSHOT</version><name>CucumberParallelExecutionTestNG</name><description>CucumberParallelExecutionTestNG</description><dependencies><dependency><groupId>io.cucumber</groupId><artifactId>cucumber-java</artifactId><version>7.7.0</version></dependency><!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java --><dependency><groupId>io.cucumber</groupId><artifactId>cucumber-testng</artifactId><version>7.7.0</version></dependency><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.10.0</version></dependency><!-- https://mvnrepository.com/artifact/org.testng/testng --><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>7.7.0</version></dependency><dependency><groupId>io.github.bonigarcia</groupId><artifactId>webdrivermanager</artifactId><version>5.3.3</version></dependency><dependency><groupId>tech.grasshopper</groupId><artifactId>extentreports-cucumber7-adapter</artifactId><version>1.2.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope></dependency><!-- https://mvnrepository.com/artifact/javax.mail/mail --><dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version></dependency></dependencies><build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.1.2</version><configuration><parallel>methods</parallel><useUnlimitedThreads>2</useUnlimitedThreads><suiteXmlFiles><suiteXmlFile>testng.xml</suiteXmlFile></suiteXmlFiles></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></pluginManagement></build></project>

CucumberRunnerTest.java
package parallel;importorg.testng.annotations.DataProvider;importio.cucumber.testng.AbstractTestNGCucumberTests;importio.cucumber.testng.CucumberOptions;@CucumberOptions(

		features ="classpath:parallel", tags ="@Login or @ForgotPassword", glue ={"parallel"},
		plugin={"pretty","json:target/cucumber-reports/cucumber.json","html:target/cucumber-reports/cucucmber-report.html"}, monochrome=true)publicclassCucumberRunnerTestextends AbstractTestNGCucumberTests {@Override@DataProvider(parallel =true)public Object[][]scenarios(){returnsuper.scenarios();}}

DriverFactory.java
package parallel;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.chrome.ChromeOptions;importio.github.bonigarcia.wdm.WebDriverManager;publicfinalclassDriverFactory{privatestatic ThreadLocal<WebDriver> driver =new ThreadLocal<>();publicstaticvoidsetDriver(){
		
		ChromeOptions options =new ChromeOptions();
		options.addArguments("--remote-allow-origins=*");//options.addArguments("--headless");
		
		WebDriverManager.chromedriver().setup();
		driver.set(new ChromeDriver(options));}publicstatic WebDriver getDriver(){return driver.get();}publicstaticvoidcloseDriver(){
		driver.get().quit();
		driver.remove();}}

Hooks.java
package parallel;importio.cucumber.java.After;importio.cucumber.java.Before;importio.cucumber.java.Scenario;publicclassHooks{@Before(order=0)publicvoidbefore(Scenario scenaio)throws Exception{
	
		
		DriverFactory.setDriver();
		System.out.println("Current Thread Name:"+Thread.currentThread().getName());
		System.out.println("Current Thread ID:"+Thread.currentThread().getId());}@After(order=0)publicvoidafter()throws Exception{
		DriverFactory.closeDriver();}}

LoginPageFactory.java
package parallel;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.support.FindBy;publicclassLoginPageFactory{public WebDriver driver;publicLoginPageFactory(WebDriver driver){this.driver= driver;}// Username locator@FindBy(xpath ="//input[@name='username']")public WebElement userName;// Password locator@FindBy(xpath ="//input[@name='password']")public WebElement passWord;// Login button locator@FindBy(xpath ="//button[@type='submit']")public WebElement loginButton;// Forgot password locator@FindBy(xpath ="//p[@class='oxd-text oxd-text--p orangehrm-login-forgot-header']")public WebElement forgotPassword;// Method that performs Username actionpublicvoidenterUsername(String uname){
		userName.sendKeys(uname);}// Method that performs Password actionpublicvoidenterPassword(String pwd){
		passWord.sendKeys(pwd);}// Method that performs Login actionpublicvoidclickLogin(){
		loginButton.click();}// Method that performs Forgot Password link verificationpublicbooleanisForgotPasswordLinkPresent(){return forgotPassword.isDisplayed();}}

LoginStepDef.java
package parallel;importorg.openqa.selenium.support.PageFactory;importorg.testng.Assert;importio.cucumber.java.en.Given;importio.cucumber.java.en.Then;importio.cucumber.java.en.When;publicclassLoginStepDef{
	LoginPageFactory login = PageFactory.initElements(DriverFactory.getDriver(), LoginPageFactory.class);@Given("User is on login page")publicvoiduser_is_on_login_page()throws InterruptedException {
		
		DriverFactory.getDriver().get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
		Thread.sleep(3000);}@When("User enters username {string}")publicvoiduser_enters_username(String username){
		login.enterUsername(username);}@When("User enters password {string}")publicvoiduser_enters_password(String password){
		login.enterPassword(password);}@When("User clicks on Login button")publicvoiduser_clicks_on_login_button(){
		login.clickLogin();}@Then("User should navigate to Orange HRM home page")publicvoiduser_should_navigate_to_orange_hrm_home_page(){
		System.out.println("Navigation to home page");}@Then("User verifies Forgot password link display")publicvoiduser_verifies_forgot_password_link_display(){
		Assert.assertTrue(login.isForgotPasswordLinkPresent());}}

  Login.feature
#Author: Sadakar Pochampalli@LoginFeatureFeature: Login page validationsBackground:    Given User is on login page@LoginScenario: Login to Orange HRM    When User enters username "Admin"And User enters password "Admin123"And User clicks on Login buttonThen User should navigate to Orange HRM home page@ForgotPasswordScenario: Forgot password link verification    Then User verifies Forgot password link display

I hope this helped you a bit. If you like it, please do subscribe my youtube channel for more tips!

Is your latest cucumber/extent report is not attached in the mail notification ? will see you in post with the tip on this.



Viewing all articles
Browse latest Browse all 261

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>