This Tutorial Explains how to Create the Gradle Project with Selenium, Writing Test Scenarios in Gherkin Syntax and Running Tests using Cucumber JVM:
In this article, we will explain about Selenium and how we can set up a Gradle project with Selenium. Contrary to the general belief, Selenium is one of the popular browser automation tools. Selenium WebDriver is an advanced version of Selenium RC, and it helps in automating tests for web applications.
Most of the DevOps teams use Gradle and define various customized tasks to run Selenium automation tests, as part of their Continuous Delivery pipeline. Therefore, in this article, we will cover the concepts of writing test scenarios (specifications) in Gherkin syntax, implementing those scenarios in Selenium Java, and running the tests using Cucumber JVM.
Finally, we will see examples of Gradle tasks to run tests. Then we can invoke these tasks from the command line or a terminal.
Table of Contents:
Create The Gradle Project
Prerequisites
We have already outlined the steps to install JDK and to configure it with IntelliJIDEA in our How To Use Gradle post where we learned about Gradle and how we use it to build, test, and publish a Java project. Therefore, we do not cover those concepts here.
Now let us download the corresponding repository from Github for a better understanding of this article.
Step #1: Open IntelliJIDEA
If IntelliJIDEA opens a default project, then close the Project and click on the launch icon again.
Step #2: Give the Github repository path in the URL text box and Download the repository.
Click on Yes on the popup, when we get a prompt on checking out the build.gradle.
We need to wait for few seconds for the IntelliJ IDEA to clone the repository on the local machine. Alternatively, we can download the zip file.
As we are testing a web application, we need to install a browser and the corresponding WebDriver binary.
Install Chrome as per the Operating System that you are using and check the version of the Chrome browser.
Download the Chromdriver binary corresponding to the version of the Chrome browser on the local machine. In this article, we are using Windows. Therefore, we have downloaded chromedriver.exe. Keep chromedriver.exe under src/test/resources folder and note down the path.
Now, we need to check that our sample web application is working. Let us check if the forgot password link is working by opening it in the Browser.
Setup Gradle Project With Cucumber JVM And Selenium
Now, we need Java bindings of Selenium and Cucumber JVM to run our tests.
So, let us configure them as outlined in the below steps:
Step #1: Open Gradle build file called build.gradle.
Step #2: Mention the dependencies outlined below.
dependencies { //testCompile group: 'junit', name: 'junit', version: '4.12' // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59' // https://mvnrepository.com/artifact/io.cucumber/cucumber-java compile group: 'io.cucumber', name: 'cucumber-java', version: '5.6.0' // https://mvnrepository.com/artifact/io.cucumber/cucumber-junit testCompile group: 'io.cucumber', name: 'cucumber-junit', version: '5.6.0' // https://mvnrepository.com/artifact/org.hamcrest/hamcrest testCompile group: 'org.hamcrest', name: 'hamcrest', version: '2.2' }
Import the changes in build.gradle, when prompted by IntelliJ IDEA. Ensure that the specified dependencies have been downloaded and added to the references.
We need to check external libraries in project explorer.
We are done with all the pre-requisites and set up for us to move ahead and write a BDD test scenario, following Gherkin syntax.
Write BDD Test Scenarios
Let us go ahead and create a feature file with two example scenarios. Create a folder called features and a file called “forgotpassword.feature” and write the Scenarios as given below:
@forgotpassword Feature: Forgot password Scenario: A valid email id is allowed Given Navigate to Page ForgotPassword When A User enters a valid email id And A User clicks on Retrieve password button Then Application shows that the email has been sent. Scenario: An invalid email is not allowed Given Navigate to Page ForgotPassword When A User enters a invalid email id And A User clicks on Retrieve password button Then Application does not show that email has been sent. # TODO - the below step is not be implemented because feature is still not available # And Application shows an error message "Invalid Email"
We need not write it as this file is already given in the sample project.
Implement BDD Specifications In Java
Let us implement these scenarios in Selenium.
Recommended Reading=> Selenium Tutorial
Create a Java class, TestSteps.java, in a package theinternet under src/test/java.
Please look at the code in the example project. We need to specify the path to the chromedriver.exe correctly.
package theinternet; import io.cucumber.java.After; import io.cucumber.java.Before; import io.cucumber.java.en.And; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import java.nio.file.Paths; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; public class ForgotPassword{ private WebDriver driver; @Before public void setUp() { System.setProperty("webdriver.chrome.driver", Paths.get("src/test/resources/chromedriver_win32/chromedriver.exe").toString()); if (driver == null) { driver = new ChromeDriver(); } } @After public void tearDown() { if (driver!=null) { driver.close(); driver.quit(); } } @Given("Navigate to Page ForgotPassword") public void navigateToPageForgotPassword() { driver.navigate().to("https://the-internet.herokuapp.com/forgot_password"); } @When("A User enters a valid email id") public void aUserEntersAValidEmailId() { driver.findElement(By.name("email")).sendKeys("valid@example.com"); } @And("A User clicks on Retrieve password button") public void aUserClicksOnRetrievePasswordButton() { driver.findElement(By.id("form_submit")).click(); } @When("A User enters a invalid email id") public void aUserEntersAInvalidEmailId() { driver.findElement(By.name("email")).sendKeys("invalid@"); } @Then("Application shows that the email has been sent.") public void applicationShowsThatTheEmailHasBeenSent() { String actualMessage = driver.findElement(By.id("content")).getText(); assertThat(actualMessage.trim(), is("Your e-mail's been sent!")); } @Then("Application does not show that email has been sent.") public void applicationDoesNotShowThatEmailHasBeenSent() { String actualMessage = driver.findElement(By.id("content")).getText(); assertThat(actualMessage.trim(), not("Your e-mail's been sent!")); } }
Run Cucumber Tests Using Gradle
Now let us create a Java Class called RunTests.java under src/test/java.
We need to mention CucumberOptions, as outlined below:
Let us look at the Java code of the RunTests Java Class.
import io.cucumber.junit.Cucumber; import org.junit.runner.RunWith; import io.cucumber.junit.CucumberOptions; @RunWith(Cucumber.class) @CucumberOptions( features = "src/test/resources/features", glue = {"theinternet"}, tags = {"@forgotpassword"}, plugin = { "pretty", "json:build/cucumber-report/cucumber.json", "html:build/cucumber-report/cucumber.html", "junit:build/cucumber-report/cucumber.xml"} ) public class RunTests { }
Ensure that we have saved all the created files.
Please check that all the files are present as per the list and path as given below:
We can run the created Selenium tests using Gradle’s build as well as test tasks. We can run the tests from the IDE as well as from the command line.
In the IDE, open RunTests Class and click on the Green play icon.
We can also open the Command line at the project’s root path and use the command as given below.
D:\softwaretestinghelp\gradle_selenium>.\gradlew.bat test --tests RunTests
Please check the test that is failing. After running the tests, we can extract the Gradle reports using its export icon in the run panel of the IntelliJ IDEA.
Html reports from the Gradle export feature are displayed below:
How To Run Cucumber Tests In Parallel?
In real-time projects, we run the tests in parallel to save time in the test execution phase of the STLC ( Software Test Life Cycle). Therefore, let us update the project to make it suitable for running tests in parallel.
Let us create a new features file, with name statuscodes.feaure, and create a Scenario Outline with three examples for the features of the application at Status Codes.
@statuscodes Feature: HTTP status codes Scenario Outline: Check the status HTTP status codes Given A User Navigates to StatusCodes Page When A User Clicks on status Code <strong><</strong>input<strong>></strong> Then Application displays the message <strong><</strong>outputCode<strong>></strong> Examples: <strong> | </strong><em>input </em><strong>| </strong><em>outputCode </em><strong>|</strong> <strong> |</strong> 200 | 200 | | 301 | 301 | | 404 | 404 <strong> | </strong>
Now, let us update the TestSteps Class under theinternet package with the below-given step implementations in Java.
@Given("A User Navigates to StatusCodes Page") public void aUserNavigatesToStatusCodesPage() { driver.navigate().to("https://the-internet.herokuapp.com/status_codes"); } @When("A User Clicks on status Code {int}") public void aUserClicksOnStatusCodeInput(Integer inputCode) { driver.findElement(By.partialLinkText(inputCode.toString())).click(); } @Then("Application displays the message {int}") public void applicationDisplaysTheMessageOutputCode(Integer outputCode) { String expectedMessage = "This page returned a "+outputCode.toString()+" status code."; String actualMessage = driver.findElement(By.cssSelector("h3 + p")).getText(); assertThat(actualMessage, containsString(expectedMessage)); }
Please look at the full file contents in the sample project, downloaded from Github.
Open build.gradle file and add Courgette-JVM under dependencies. Courgette-JVM makes it possible to run cucumber tests in parallel. Mention it under dependencies and import the changes in build.gradle file.
// https://mvnrepository.com/artifact/io.github.prashant-ramcharan/courgette-jvm compile group: 'io.github.prashant-ramcharan', name: 'courgette-jvm', version: '4.6.2'
The dependencies block in the Gradle build needs to be as shown below.
dependencies { //testCompile group: 'junit', name: 'junit', version: '4.12' // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59' // https://mvnrepository.com/artifact/io.cucumber/cucumber-java compile group: 'io.cucumber', name: 'cucumber-java', version: '5.6.0' // https://mvnrepository.com/artifact/io.cucumber/cucumber-junit testCompile group: 'io.cucumber', name: 'cucumber-junit', version: '5.6.0' // https://mvnrepository.com/artifact/org.hamcrest/hamcrest testCompile group: 'org.hamcrest', name: 'hamcrest', version: '2.2' // https://mvnrepository.com/artifact/io.github.prashant-ramcharan/courgette-jvm compile group: 'io.github.prashant-ramcharan', name: 'courgette-jvm', version: '4.6.2' }
Check whether Courgette-JVM has been downloaded and accessible under the external libraries section. We can check that in the project explorer of the IDE, as shown in the below image.
Create a Java Class similar to RunTests.java with the code given below and save it with the name RunParallelTests.java at src/test/java. We need to copy the code as shown below and paste that into the file.
import courgette.api.CourgetteOptions; import courgette.api.CourgetteRunLevel; import courgette.api.junit.Courgette; import courgette.api.CucumberOptions; import org.junit.runner.RunWith; @RunWith(Courgette.class) @CourgetteOptions( threads = 10, runLevel = CourgetteRunLevel.FEATURE, showTestOutput = true, reportTargetDir = "build/parallel", cucumberOptions = @CucumberOptions( features = "src/test/resources/features", glue = "theinternet", tags = {"@statuscodes or @forgotpassword"}, plugin = { "pretty", "json:build/cucumber-report/cucumber.json", "html:build/cucumber-report/cucumber.html", "junit:build/cucumber-report/cucumber.xml"} ) ) public class RunParallelTests { }
We use Courgette JVM’s API to define its options, similar to Cucumber JVM. Please notice the CucumberOptions annotation inside CourgetteOptions. We have kept all parameters the same as earlier other than parameter called tags. Now we have included the new feature too.
Important here is to notice that Courgette JVM has a parameter called runLevel. We can use runLevel to run the tests on either a Scenario or a Feature level.
Feature Level
Let us first run our tests in parallel on the Feature level. Once we start running the tests, we should be able to notice that tests of both the Features are running in 02 separate browser instances.
Use the below-given command from the project’s root directory to run tests using Gradle. However, we can use the IDE too to run these tests.
D:\softwaretestinghelp\gradle_selenium>.\gradlew.bat test --tests RunParallelTests
Notice the reports folder, as stated in the configurations of Courgette-JVM. Please check the reports under build/parallel directory.
Scenario Level
Once we run the parallel tests on the Scenario level, Courgette-JVM runs all the scenarios in our feature files in parallel in separate browser instances. Update CourgetteOptions as shown below in RunParallelTests.java
runLevel = CourgetteRunLevel.SCENARIO,
Again use the below-given command from the project’s root directory to run tests using Gradle.
D:\softwaretestinghelp\gradle_selenium>.\gradlew.bat test --tests RunParallelTests
Check the reports under the build/parallel directory and notice the time difference.
Note that the time taken by these tests to run and complete is dependent on the memory configuration present on the target machine.
Conclusion
We have explained the steps to create and run a Gradle project with Selenium. We have taken very simple to understand examples, in this article. We have also provided the source code for the example project under the MIT license. You can download it from here.
We have also covered the concepts on running Selenium tests using Courgette JVM in parallel both at the scenario and feature level.