Search code examples
seleniumgradlebuild.gradlebuild-automationgradle-plugin

I need to run cucumber feature files in parallel using gradle


I am working on automation which is based on Cucumber, gradle. I am Unable to execute the feature files in parallel not sure what needs to done. But I am able to run/execute feature files sequentially.

Can somebody please look into this issue and provide me some inputs.


**Below is my build.gradle file** 

        

    plugins {
            id 'java'
            id 'maven-publish'
            //id 'java-library'
            //id 'io.qameta.allure' version '2.8.1'
        
        }
        
        
        repositories {
            mavenCentral()
            jcenter()
        }
        
        task deleteGraphicsAssets(type: Delete) {
            delete "build"
        }
        
        task allureHistoryCopy() {
            mkdir "./allure-results/history"
            copy {
                from "./allure-report/history"
                into "./allure-results/history/"
            }
        }
        
        group 'com.hal.brands'
        version '1.0-SNAPSHOT'
        sourceCompatibility = 1.8
        
            
        def cucumberVersion = '4.8.0'
        def gherkinVersion  = '5.1.0'
        def hamcrestVersion = '1.3'
        
        def testngVersion = '6.14.3'
        def cucumber4adapterVersion = '1.0.11'
        
        def Log4jVersion = '1.2.17'
        def slf4jVersion = '1.7.5'
        
        def restassuredVersion = '3.3.0'
        def jsonsimpleVersion = '1.1.1'
        
        def appiumjavaClientVersion = '7.3.0'
        
        def allurePluginVersion = '2.8.1'
        def allurecucumber4jvmVersion = '2.13.0'
        def codeborneselenideVersion = '5.3.1'
            
        
        dependencies {
        
            //All version of the dependencies are defined above
        
            //Cucumber
            testImplementation  "io.cucumber:cucumber-java:${cucumberVersion}"
            testImplementation  "io.cucumber:cucumber-jvm:${cucumberVersion}"
            testImplementation  "io.cucumber:cucumber-core:${cucumberVersion}"
            testImplementation  "io.cucumber:cucumber-testng:${cucumberVersion}"
        
            implementation  "io.cucumber:cucumber-picocontainer:${cucumberVersion}"  //Do not change from implementation to testImplementation otherwise Scenario will throw errors
        
            //Cucumber Gherkin
            testImplementation  "io.cucumber:cucumber-gherkin:${gherkinVersion}"
        
            //Hamcrest
            testImplementation "org.hamcrest:hamcrest-all:${hamcrestVersion}"
        
        
            //TestNg
            //testImplementation "org.testng:testng:${testngVersion}"
            //testCompile group: 'org.testng', name: 'testng', version: '6.13.1'
        
        
            //Cucumber Adapter Extent Reports
            //testImplementation  'com.aventstack:extentreports:4.0.9'   // Do not use this when you are using Cucumber Adapter Extent reports. Not Required when Adapter used
            testImplementation  "com.aventstack:extentreports-cucumber4-adapter:${cucumber4adapterVersion}"
        
        
            //Log4j Logs
            implementation "log4j:log4j:${Log4jVersion}"  //Do not change from implementation to testImplementation otherwise  PropertyConfigurator and Logger will throw errors
        
            //Rest Assured Apis
            testImplementation "io.rest-assured:rest-assured:${restassuredVersion}"
            testImplementation "com.googlecode.json-simple:json-simple:${jsonsimpleVersion}"
            testImplementation 'org.json:json:20180813'
        
        
            //Selenium Apis
            compile group: 'org.seleniumhq.selenium', name: 'selenium-server', version: '3.141.59'
            implementation 'com.paulhammant:ngwebdriver:1.1.4'
            compile group: 'org.seleniumhq.selenium', name: 'selenium-htmlunit-driver', version: '2.52.0'
            implementation 'org.seleniumhq.selenium:selenium-java:3.141.59'
        
        
            //Allure Reports
            testImplementation "io.qameta.allure:allure-cucumber4-jvm:${allurecucumber4jvmVersion}"
            implementation "io.qameta.allure:allure-selenide:${allurecucumber4jvmVersion}"
            implementation "com.codeborne:selenide:${codeborneselenideVersion}"
        
        
            //Appium
            implementation "io.appium:java-client:${appiumjavaClientVersion}"
        
        
            //Netty Jar is important
            compile group: 'io.netty', name: 'netty-all', version: '4.1.31.Final'
        
            //AspectJweaver
            runtime group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.6'
        
            compile group: 'com.browserstack', name: 'browserstack-integration', version: '1.0.0'
            compile group: 'com.browserstack', name: 'browserstack-local-java', version: '0.3.0'
        
            //MongoDB
            // https://mvnrepository.com/artifact/org.mongodb/mongodb-driver
            // compile group: 'org.mongodb', name: 'mongodb-driver', version: '3.12.6'
            // compile group: 'org.mongodb', name: 'mongodb-driver', version: '3.4.2'
        
            // https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver
            compile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.12.6'
        
            //SqlServer
            // https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc
            compile group: 'com.microsoft.sqlserver', name: 'mssql-jdbc', version: '7.2.1.jre8'
        
            // https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple
            compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
        
        
        
            //SqlServer
            // https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc
            compile group: 'com.microsoft.sqlserver', name: 'mssql-jdbc', version: '7.2.1.jre8'
        
        
             compile fileTree(dir: 'libs', include: 'testng-6.14.3.jar')   //This should be last statement
           
        }
        
        
        configurations {
            cucumberRuntime.extendsFrom testImplementation
        }
        
        
        
        task runTest() {
            dependsOn assemble, testClasses
            doLast {
                javaexec {
                    main = "io.cucumber.core.cli.Main"
                    classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
        
                    systemProperty "environment", project.findProperty("env") ?: "QA"
                    systemProperty "platform", project.findProperty("plt")  ?: "browserstack"
                    
                    
        
                    args = [
        
                             '--threads' , '2',
                          
                          
                            '--plugin', 'pretty',
        
                            '--plugin', 'json:target/HAL.json',
        
                            //'--plugin', 'io.qameta.allure.cucumber4jvm.AllureCucumber4Jvm',
        
                            '--plugin', 'com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:Report',
        
                            '--glue',   'com.pros.InitDriver',
        
                            '--glue',   'com.pros.helper.Logger',
        
                            '--glue',   'com.pos.it.helper',
        
                            '--glue',   'com.bpos.test.stepdefinition',
        
                            '--glue',   'src/main/java','src/test/resources','src/main/resources',
        
                            '--tags',    project.findProperty("testTag")  ?: "@sanity"
        
                    ]
        
                }
        
            }
        }
        
         /*
        
            allure {
                System.setProperty( "user.dir", project.projectDir.toString() )
                version = allurePluginVersion
                autoconfigure = true
                aspectjweaver = true
                //boolean clean = true
                resultsDir = file("${project.projectDir}/allure-results");
                println "resultsDir : ${resultsDir}"
                reportDir = file("${project.projectDir}/allure-report");
                println "reportDir : ${reportDir}"
                String configuration = 'testImplementation'
                useTestNG {
                    version = '2.0-BETA10'
                }
                useCucumberJVM {
                    version = '2.0-BETA10'
                }
            }
        
           runTest.finalizedBy 'allureReport'
         */
        
        
        task packageZip(type: Zip){
        
        
            from "$project.rootDir/Automation_Report"
            print "$project.rootDir\n"
            destinationDir = file("$project.rootDir/Archive")
            Date date = new Date()
            String datePart = date.format("yyyyMMdd")
            String timePart = date.format("HHmmss")
            println "datePart : " + datePart + "\ttimePart : " + timePart
        
            archiveName = datePart+"_"+timePart+"_"+"IST.zip"
        
            //  archiveName = "datePart_timePart_IST.zip"
            println "Zip action complete"
        }
        
        
        
        
        tasks.test {
        
            // finalizedBy runTest
            finalizedBy packageZip
        
        }


**Below the sample command that I use in command prompt**
gradle runTest -PtestTag=@sanity_ui -Penv=STAGE -Pplt=Local

**Below is my project Hierarchy**

[![enter image description here][1]][1]

I am not sure as what need to be included in args section in build.gradle file so that it kicks of parallel execution.


Solution

  • My recent answer to this closely related question should be helpful here: https://stackoverflow.com/a/65473008/10256045

    There is a bit of setup needed to get cucumber running in parallel properly with gradle.

    • Every test has to be threadsafe so you need to be careful with static usage.
    • Multiple drivers need to be made for each thread
    • logging needs to log the correct thread and scenario

    I have a skeleton framework that handles all of this that you can use as a reference or build from here

    For your specific question in the build.gradle you determine the --threads cucumber option.

    Take a look in the build.gradle here

    These variables are used to setup parallel runs and determine threads to use in the cucumber options

    def availableThreadCount = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
    def cucumberThreadsOption = ['--threads', availableThreadCount.toString()]
    

    if runInParallel task is used it puts setParallel to true. We then add the --threads arg into the cucumber options This is where that happens in the cucumber task

    Here is where the built cucumber options are used

    CreateSharedDrivers.java here is where we handle creating multiple drivers for threads and have the shutdown hook implemented.

    In Hooks.java here there is an example of how we log the thread and its current scenario