QA Automation/Manual: API and Web/UI : Java, Cucumber, Selenium, Junit, TestNG, Java Script, Postman/Newman, Maven, TestLink, Azure Test Plans, Jira, AutoIT
CI/CD: Azure DevOps, Team City, Batch Scripting, Perl Scripting, Chef
Business Intelligence : Jaspersoft, Pentaho, Tableau, Power BI | Reports, Dashboards, Analysis, Data Integration, ETL
Cloud Computing & OS : AWS, Cent OS
The following worked for me with the dependencies mentioned in pom.xml
If you are on 7.8.0 TestNG downgrade it to 7.7.0
or
do not take testng dependency rather take cucumber-testng and cucumber-java both versioned 7.12.0
Eclipse console log:
[RemoteTestNG] detected TestNG version 7.8.0SLF4J: Failed to load class"org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
java.lang.NoSuchMethodError:'void org.testng.TestRunner.<init>(org.testng.internal.IConfiguration, org.testng.ISuite, org.testng.xml.XmlTest,boolean, java.util.Collection, java.util.List)'
at org.testng.remote.support.RemoteTestNG6_12$1.newTestRunner(RemoteTestNG6_12.java:33)
at org.testng.remote.support.RemoteTestNG6_12$DelegatingTestRunnerFactory.newTestRunner(RemoteTestNG6_12.java:66)
at org.testng.ITestRunnerFactory.newTestRunner(ITestRunnerFactory.java:52)
at org.testng.SuiteRunner$ProxyTestRunnerFactory.newTestRunner(SuiteRunner.java:720)
at org.testng.SuiteRunner.init(SuiteRunner.java:224)
at org.testng.SuiteRunner.<init>(SuiteRunner.java:116)
at org.testng.TestNG.createSuiteRunner(TestNG.java:1375)
at org.testng.TestNG.createSuiteRunners(TestNG.java:1349)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1191)
at org.testng.TestNG.runSuites(TestNG.java:1114)
at org.testng.TestNG.run(TestNG.java:1082)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
<!-- Comment testng dependency since pom already has cucumber-testng or
you could enable the dependency with downgraded version 7.7.0
--><!-- https://mvnrepository.com/artifact/org.testng/testng --><!-- <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</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><suiteXmlFiles><suiteXmlFile>testng.xml</suiteXmlFile></suiteXmlFiles></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><source>17</source><target>17</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.1.1</version><configuration><archive><manifest><addClasspath>true</addClasspath><mainClass>runners.CucumberRunnerCLI</mainClass></manifest><manifestEntries><Class-Path>.</Class-Path></manifestEntries></archive><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></pluginManagement></build></project>
Hi, In this post, we can see how to use JVM shut down hook with in cucumber Hooks.
What is JVM shut down hook ? (Definition credits : geeksforgeeks.org) A special construct that facilitates the developers to add some code that has to be run when the Java Virtual Machine (JVM) is shutting down is known as the Java shutdown hook.
Begin with some interesting questions ! 1) Did you ever think of refreshing a folder in java coding to send latest run cucumber report or extent report ? 2) Did you keep your email notification code in cucumber After or AfterAll hook and tried sending email but ended-up with old report in mail inbox ? 3) How did you solve this problem with Cucumber, TestNG integration ?
Perhaps! There might be other solutions and could be better ones. My approach was, effectively make use of JVM shut down hook with in cucumber AfterAll hook to have the latest run report attached and sent over the email.
It started with, What is cucumber AfterAll hook ?
AfterAll is a cucumber hook that run after all scenarios have been executed.
@AfterAllpublicstaticvoidafterAll(){// Runs after all scenarios}
JVM Shutdown hook basic example: In the below program, there are two print statements.
By using addShutdownHook JVM would print "This text prints before shutdown!" firstly and at the time JVM shut down it prints "Shutdown Hook is running and this prints at last!"
That is, statements inside run() method executes at the very end.
publicclassShutDownHook{publicstaticvoidmain(String[] args){Runtime.getRuntime().addShutdownHook(new Thread(){publicvoidrun(){
System.out.println("Shutdown Hook is running and this prints at last!");}});
System.out.println("This text prints before shutdown!");}}
Below is the combined implementation of @AfterAll cucumber hook and JVM addShutdownHook. In the run() method, keep the email triggering code so the selenium execution always picks the latest report to be sent in the mail. It pretty much worked through jar execution too.
package parallel;importjava.net.InetAddress;importjava.net.UnknownHostException;importio.cucumber.java.After;importio.cucumber.java.AfterAll;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();}@AfterAll(order =0)publicstaticvoidafterAll()throws UnknownHostException {
System.out.println("AfterAll - with order=0");
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("System IP Address : "+(localhost.getHostAddress()).trim()); Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(){@Overridepublicvoidrun(){
System.out.println("Shutdown Hook is running and this text prints before JVM shut downs!");}}));
System.out.println("This text prints before Shutdown hook");}}
Eclipse logs:
[RemoteTestNG] detected TestNG version 7.7.0
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
@LoginFeature @ForgotPassword
Scenario: Forgot password link verification # parallel/Login.feature:16
@LoginFeature @Login
Scenario: Login to Orange HRM # parallel/Login.feature:9
Jun 11, 2023 1:01:23 AM org.openqa.selenium.remote.service.DriverService$Builder getLogOutput
INFO: Driver logs no longer sent to console by default; https://www.selenium.dev/documentation/webdriver/drivers/service/#setting-log-output
Jun 11, 2023 1:01:23 AM org.openqa.selenium.remote.service.DriverService$Builder getLogOutput
INFO: Driver logs no longer sent to console by default; https://www.selenium.dev/documentation/webdriver/drivers/service/#setting-log-output
Current Thread Name:TestNG-PoolService-0
Current Thread ID:16
Current Thread Name:TestNG-PoolService-1
Current Thread ID:17
Given User is on login page # parallel.LoginStepDef.user_is_on_login_page()
When User enters username "Admin" # parallel.LoginStepDef.user_enters_username(java.lang.String)
Given User is on login page # parallel.LoginStepDef.user_is_on_login_page()
Then User verifies Forgot password link display # parallel.LoginStepDef.user_verifies_forgot_password_link_display()
And User enters password "Admin123" # parallel.LoginStepDef.user_enters_password(java.lang.String)
And User clicks on Login button # parallel.LoginStepDef.user_clicks_on_login_button()
Navigation to home page
Then User should navigate to Orange HRM home page # parallel.LoginStepDef.user_should_navigate_to_orange_hrm_home_page()
AfterAll - with order=0
System IP Address : 192.168.1.8
This text prints before Shutdown hook
┌──────────────────────────────────────────────────────────────────────────┐
│ View your Cucumber Report at: │
│ https://reports.cucumber.io/reports/213e45d0-8053-4753-b2c4-78f40d98bd71 │
│ │
│ This report will self-destruct in 24h. │
│ Keep reports forever: https://reports.cucumber.io/profile │
└──────────────────────────────────────────────────────────────────────────┘PASSED: io.cucumber.testng.AbstractTestNGCucumberTests.runScenario("Login to Orange HRM", "Login page validations")
Runs Cucumber Scenarios
PASSED: io.cucumber.testng.AbstractTestNGCucumberTests.runScenario("Forgot password link verification", "Login page validations")
Runs Cucumber Scenarios
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 2, Passes: 2, Failures: 0, Skips: 0
===============================================
Shutdown Hook is running and this text prints before JVM shut downs!
I hope this helped you a bit! If you like it, please do Subscribe my YouTube channel for interesting updates.
Hi, In this post, we will see how to run cucumber scenarios in parallel with TestNG.
What is parallel testing in cucumber? Parallel testing in Cucumber refers to the ability to execute Cucumber scenarios in parallel, allowing multiple scenarios to run simultaneously and speeding up the overall test execution time.
Consider below factors while implementing parallel execution.
Example: 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.
Is it necessary to have testng.xml for parallel execution ? There could be different approaches to perform parallel execution from command line or jar file or from CI/CD method, in this demo I'd say yes it is necessary to have testng.xml so that we can pass dynamic thread count.
What is ThreadLocal webdriver in cucumber ? Why it is important ?
A ThreadLocal webdriver refers to an instance of a WebDriver object that is stored in a ThreadLocal variable.
Each thread running a Cucumber scenario or step can have its own WebDriver instance, isolated from other threads.
This approach ensures thread safety and prevents conflicts when executing scenarios in parallel.
Here's why ThreadLocal webdriver is important
Thread Safety
Parallel Execution
Resource Management
Scenario Isolation
The project folder structure: Is mandatory to keep all the code in "parallel" folder as in many example over the internet ? No, it is not necessary to keep them in "parallel" folder. Similarly to keep the features NO "parallel" folder is required.
Concepts covered in code base:
DriverFactory for chrome and edge - How to pass chrome or edge as command line argument ?
Parallel execution configurations - Where and how to configure parallel execution with TestNG?
POM model with page factory pattern - How to isolate locators and step definitions ?
Cucumber hooks - What is the recommendation of cucumber hooks over TestNG hooks ?
Reports
Which report is to be used - cucumber reports or extent reports ? cucumber reports
Where to write email code to send the latest reports ? In JVM shutdown hook that is written in cucumber AfterAll hook (Did you ever try to remove or refresh a folder to have the latest reports to be sent over email)
How to run the project ?
Through command line
Through eclipse run as TestNG
Through executable jar file
Would you like to watch few mins demo in a no voice video ?
Jumping on to the core of this article i.e., parallel testing
Parallel execution configurations:
(For complete code download project from GitHub or Use this link to download as Zip)
Declare thread local driver in WebDriverFactory java class and then set, get and remove instances of the driver.
privatestatic ThreadLocal<WebDriver> driver = new ThreadLocal<>();
Override the DataProvider annotation with parallel=true in CucumberRunnerTest that extends AbstractTestNGCucumberTests class.
In pom.xml add the testng.xml as suiteXml file in maven-surefire-plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
That's all we need to make cucumber scenarios to run parallel with TestNG as testing framework. So, after configurations - How to run the code to see parallel execution ?
On the command prompt - maven execution
Navigate to the the project folder location - you should have the pom.xml in it.
Run below command in Command prompt.
mvn -Dbrowser=chrome -Ddataproviderthreadcount=2 test
This command opens two chrome browser parallelly as passing dataproviderthreadcount =2
If passed 1 then sequential execution takes place.
On the command prompt - jar execution
Use the maven-assembly-plugin and Main.run method creation technique to create a jar file (scroll down to the complete code section below and see how assembly plugin is configured in pom.xml and how Main.main takes arguments in CucumberRunnerCLI.java class )
Now to create executable/runnable jar file give below goal in eclipse (Runs As -> Maven build -> Goals) (Note: Make sure to clean the project prior assembling)
Running above command downloads required jar files in .m2 repository and creates and copy the jar file in target folder.
[[1;34mINFO[m] Building jar: E:\Automation\CucumberParallelExecutionTestNG\
target\CucumberParallelExecutionTestNG-0.0.1-SNAPSHOT-jar-with-dependencies.jar
In the Eclipse Run As TestNG with Run Configurations
Run As -> TestNG -> Run Configurations -> VM Arguments --> -Dbrowser=chrome -Ddataproviderthreadcount=2
This is how one could able to run the scenarios in parallel with TestNG as the testing framework.
Interesting Research Observations:
Over the internet there are bunch of suggestions with maven sure fire plugin to play with parallel=method, threadCount=3 and incase of maven fail safe plugin to play with dataproviderthreadcount and value in the properties those didn't work for me at least.
i.e., None of the below configurations worked to run scenarios parallel.
maven-surefire-plugin with parallel=true and threadCount=3 DID NOT work<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<parallel>methods</parallel>
<threadCount>3</threadCount>
<perCoreThreadCount>false</perCoreThreadCount>
<useUnlimitedThreads>false</useUnlimitedThreads>
</configuration>
</plugin>
maven-failsafe-plugin with dataproviderthreadcount property with value DID NOT work.
#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
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd"><suitename="Suite"parallel="true"data-provider-thread-count="1"verbose="2"><testname="Test"><classes><classname="runners.CucumberRunnerTest"/></classes></test><!-- Test --></suite><!--Suite -->
package hooks;importjava.net.InetAddress;importjava.net.UnknownHostException;importdriverfactory.WebDriverFactory;importio.cucumber.java.After;importio.cucumber.java.AfterAll;importio.cucumber.java.Before;importio.cucumber.java.Scenario;publicclassHooks{@Before(order =0)publicvoidbefore(Scenario scenaio)throws Exception {
WebDriverFactory.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 {
WebDriverFactory.closeDriver();}@AfterAll(order =0)publicstaticvoidafterAll()throws UnknownHostException {
System.out.println("AfterAll - with order=0");
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("System IP Address : "+(localhost.getHostAddress()).trim());
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable(){@Overridepublicvoidrun(){
System.out.println("Write email code in this method - Shutdown Hook is running and this text prints before JVM shut downs!");}}));
System.out.println("This text prints before Shutdown hook");}}