The previous tutorial will have explained to run Cucumber tests with JUnit4 or TestNG from Command-Line. Cucumber7 with JUnit5 has a lot of new configuration options. This tutorial will cover all the possible options.
Below is the sample CucumberRunnerTests class for JUnit5.
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/example")
@SelectClasspathResource("/features")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example")
public class CucumberRunnerTests {
}
Run Test from Command Line
1. Open the command prompt and change the directory to the project location where pom.xml is present.
cd C:\Users\Vibha\eclipse-workspace_personnel\Cucumber7JUnit5_Demo
2. All feature files should be in src/test/resources and create the Cucumber Runner class as CucumberRunnerTest. Note:- The Runner class name should end with Test to execute the tests from Command Line Run the following command in the command prompt:
mvn clean test
mvn clean test runs Cucumber Features using Cucumber’s JUnit Runner.
3. The below screenshot shows the build success output.
Overriding Cucumber Options
Cucumber provides several options that can be passed to on the command line.
1. Running Scenarios using Tags from Command Line
If you are using Maven and want to run a subset of scenarios tagged with @ValidCredentials.
mvn clean test -Dcucumber.filter.tags="@ValidCredentials"
2. Running a Feature file from Command Line
Suppose you want to run a single Feature File from the command line, then use the below syntax
mvn clean test -Dcucumber.features=src/test/resources/features/LoginPage.feature
3. Passing plugin from Command Line
If we want to pass a plugin, please use the below-specified command:
mvn clean test -Dcucumber.plugin=html:target/cucumber-reports/cucumberReport.html
You can see that the cucumberReport.html is generated by the plugin.
4. Passing multiple Parameter from Command Line
If we want to pass more than one parameter, then we can use the following command
mvn clean test -Dcucumber.features=src/test/resources/features/LoginPage.feature -Dcucumber.filter.tags="@ValidCredentials"
You can see that only 1 test is executed and rest 4 tests are skipped out of total 5 tests as shown in the Report.
5. Running a Scenario without a tag from Command Line
If we want to run a single Scenario from the command line and no tag is assigned to that scenario, this is how we specify
mvn clean test -Dcucumber.features=src/test/resources/features/LoginPage.feature:11
6. Ignoring a subset of scenarios
If we do not want to run any Scenario from the command line, this is how we specify
mvn clean test -Dcucumber.filter.tags="not @ValidCredentials"
There is a total of 5 tests, but only 4 will be executed and 1 will be skipped. The output of the above program is shown below:
7. Pass glue code through command line
If we want to pass glue code from the command line, this is how we specify
mvn clean test -Dcucumber.glue=com.example
8. Pass dry run value through command line
dry-run option can either be set as trueor false. If it is set as true, it means that Cucumber will only check that every step mentioned in the Feature File has corresponding code written in the Step Definition file or not. By default, dry-run is False.
mvn clean test -Dcucumber.execution.dry-run=true
This image shows the steps in the feature file that does not have step definitions.
The cucumber report shows that out of 2 tests, 1 is executed and another one is undefined.
9. Pass snippet type value through command line
The default option for snippets is UNDERSCORE. This settings can be used to specify the way code snippets will be created by Cucumber.
mvn clean test -Dcucumber.snippet-type=camelcase
You can see that the code snippet is in camelCase. In the previous example, it underscored.
That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Spring Boot 3.0.4 requires Java 17 and is compatible with and including Java 19. Spring Framework 6.0.6 or above is also required.
Explicit build support is provided for the following build tools:
Maven – 3.5+
Gradle – 7.x (7.5 or later) and 8.x
This framework consists of
SpringBoot Starter Parent – 3.1.0
Serenity Rest Assured – 3.6.12
Spring
Java 17
Gradle – 7.6.1
JUnit Jupiter API – 5.9.2
JUnit Jupiter Engine – 5.9.2
Serenity JUnit5 – 3.6.12
What is SpringBoot Application?
Spring Boot is an open-source micro-framework that provides Java developers with a platform to get started with an auto-configurable production-grade Spring application.
Comes with embedded HTTP servers like Tomcat orJetty to test web applications.
Adds many plugins that developers can use to work with embedded and in-memory databases easily. Spring allows you to easily connect with database and queue services like Oracle, PostgreSQL, MySQL, MongoDB, Redis, Solr, ElasticSearch, Rabbit MQ, and others.
Project Directory Structure
Implementation Steps
Create a source folder – src/test/resources to create properties file
AddSpringBootTest, SerenityRest Assured, and Serenity-JUnit5 dependencies to the project
Create the Test classes.
Create an application.properties file in src/test/resources
Run the tests from JUnit5
Run the tests from Command Line
Serenity Report Generation
Step 1 – Create a source folder – src/test/resources to create test scenarios in the Feature file
Right-click on the test directory and select New->Directory and select resources (Maven Source Directories).
Step 2 – Add SpringBootTest,Rest Assured, and allure dependencies to the project
We have added SpringBootTest, SpringBoot Web, Tomcat, Spring Web, Rest Assured, and Serenity-JUnit5 dependencies to the build.gradle.
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.0-SNAPSHOT'
id 'io.spring.dependency-management' version '1.1.0'
id 'net.serenity-bdd.serenity-gradle-plugin' version '3.6.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-tomcat'
implementation 'org.springframework:spring-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'net.serenity-bdd:serenity-junit5:3.6.12'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.2'
testImplementation 'net.serenity-bdd:serenity-core:3.6.12'
testImplementation 'net.serenity-bdd:serenity-rest-assured:3.6.12'
testImplementation 'net.serenity-bdd:serenity-spring:3.6.12'
}
tasks.named('test') {
useJUnitPlatform() {}
testLogging {
showStandardStreams = true
}
systemProperties System.getProperties()
}
gradle.startParameter.continueOnFailure = true
test.finalizedBy(aggregate)
Step 3 – Create the Test classes
uses @SpringBootTest annotation which loads the actual application context.
uses WebEnvironment.RANDOM_PORT to create and run the application at some random server port.
@LocalServerPort gets the reference of the port where the server has started. It helps in building the actual request URIs to mimic real client interactions.
Below is the Test Class, created in the src/test/java directory.
import io.restassured.response.ValidatableResponse;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import static io.restassured.RestAssured.given;
@ExtendWith(SerenityJUnit5Extension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringBootDemoDefinitions {
private final static String BASE_URI = "http://localhost:";
@LocalServerPort
private int port;
@Value("${server.servlet.context-path}")
private String basePath;
private ValidatableResponse response;
@Test
public void verifyController1() throws Exception {
response = given().contentType("application/json")
.header("Content-Type", "application/json")
.when().get(BASE_URI + port + basePath+ "/").then().statusCode(200);
String Actual = response.extract().asString();
System.out.println("Result :"+Actual);
Assertions.assertEquals("Hello World, Spring Boot!", Actual);
}
@Test
public void verifyController2() throws Exception {
response = given().contentType("application/json")
.header("Content-Type", "application/json")
.when().get(BASE_URI + port + basePath+ "/qaautomation").then().statusCode(200);
String Actual = response.extract().asString();
System.out.println("Result :"+Actual);
Assertions.assertEquals("Hello QA Automation!", Actual);
}
}
This class sends the request and receives a response after performing the GET operation. Here, the validation of the response also takes place by asserting the expected and actual response
Step 4 – Create an application.properties file in src/test/resources
Application.properties is created under src/ test/java.
spring.profiles.active – property to specify which profiles are active. The default profile is always active. server.port – By default, the embedded server starts on port 8080. Now the server will start on port 8090 server.servlet.context-path – the context path in Spring Boot can be changed by setting a property, server.servlet.context-path.
Step 5 – Run the tests from JUnit5
Right-click on the Test class and select Run ‘SpringBoot_Tests’.
The output of the above program is
This image shows that the profile name is “test”. Application is started on port – “65221” and the context path is “/demo”.
Step 6 – Run the tests from Command Line
Run the tests from the command line by using the below command
gradle clean test
The output of the above program is
Step 7 – Serenity Report Generation
The best part about Serenity is the report generation by it. The Reports contain all possible type of information, you can think of with minimal extra effort. There is multiple types of reports are generated. We are interested in index.html .
Below is the new Serenity Report.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
Spring Boot is an open-source micro-framework that provides Java developers with a platform to get started with an auto-configurable production-grade Spring application.
Comes with embedded HTTP servers like Tomcat orJetty to test web applications.
Adds many plugins that developers can use to work with embedded and in-memory databases easily. Spring allows you to easily connect with database and queue services like Oracle, PostgreSQL, MySQL, MongoDB, Redis, Solr, ElasticSearch, Rabbit MQ, and others.
Project Directory Structure
What is RestController?
HTTP requests are handled by a controller in Spring’s approach to building RESTful web services. The @RestController annotation identifies these components, and the GreetingController shown below (from src/main/java/com/example/springboot_demo/HelloController.java) handles GET requests for / and /qaautomation by returning a new instance of the Greeting class. Spring RestController takes care of mapping request data to the request-defined handles method.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping(path="/")
String hello() {
return "Hello World, Spring Boot!";
}
@GetMapping(path="/qaautomation")
String qaautomation() {
return "Hello QA Automation!";
}
}
Implementation Steps
Create a source folder – src/test/resources to create properties file
AddSpringBootTest, Serenity and JUnit5 dependencies to the project
Create the Test and Helper classes.
Create an application.properties file in src/test/resources
Create serenity.properties at the root of the project
Run the tests from JUnit5
Run the tests from Command Line
Serenity Report Generation
Step 1 – Create a source folder – src/test/resources to create test scenarios in the Feature file
Right-click on the test directory and select New->Directory and select resources (Maven Source Directories).
Step 2 – Add SpringBootTest, Serenity, and JUnit5 dependencies to the project
We have added SpringBootTest, Serenity, Rest Assured, and JUnit5 dependencies to pom.xml.
uses @SpringBootTest annotation which loads the actual application context.
uses WebEnvironment.RANDOM_PORT to create and run the application at some random server port.
@LocalServerPort gets the reference of the port where the server has started. It helps in building the actual request URIs to mimic real client interactions.
Below is the code of the StepDefinition and Helper class. These classes are created in the src/test/java directory.
This class sends the request and receives a response after performing the GET operation. Here, the validation of the response also takes place by asserting the expected and actual response
Step 4 – Create an application.properties file in src/test/resources
Application.properties is created under src/test/resources for the test profile. If you want to run the SpringBootApplication from DEV profile, then create application.properties file in src/main/resources.
spring.profiles.active – property to specify which profiles are active. The default profile is always active. server.port – By default, the embedded server starts on port 8080. Now the server will start on port 8090 server.servlet.context-path – the context path in Spring Boot can be changed by setting a property, server.servlet.context-path.
Step 5 – Create serenity.properties at the root of the project
serenity.project.name = Testing of SpringBoot Application with Serenity and JUnit5 Demo
Step 6 – Run the tests from JUnit5
Right-click on the Test class and select Run ‘SpringBootDemoApplicationTests’.
The output of the above program is
This image shows that the profile name is “test”. Application is started on port – “58458” and the context path is “/demo”.
Step 7 – Run the tests from Command Line
Run the tests from the command line by using the below command
mvn clean verify
The output of the above program is
Step 8 – Serenity Report Generation
The serenity test reports are generated under target/site/serenity.
Below is the sample Index.html Report.
Go to Test Results, present at the top left of the index.html page.
Serenity Reports are living documentation that contains the meaningful report for each Test. It illustrated narrative reports that document and describe what your application does and how it works.
Environment variables JAVA_HOME and GRADLE_HOME are correctly configured
This framework consists of:
Java 11
JUnit Jupiter – 5.8.2
JUnit Jupiter Engine – 5.8.2
Gradle – 7.3.3 (Build Tool)
Selenium – 4.3.0
Steps to set up Gradle Java Project for Selenium and JUnit5
Download and Install Java on the system
Download and setup Eclipse IDE on the system
Setup Gradle on System
Create a new Gradle Project
Add Selenium and JUnit5 dependencies to the Gradle project
Create Pages and Test Code for the pages
Run the tests from Command Line
Gradle Report generation
Project Structure
Implementation Steps
Step 1- Download and Install Java
Selenium needs Java to be installed on the system to run the tests. Click here to know How to install Java.
Step 2 – Download and setup Eclipse IDE on the system
The Eclipse IDE (integrated development environment) provides strong support for Java developers. Click here to know How to install Eclipse.
Step 3 – Setup Gradle
To build a test framework, we need to add several dependencies to the project. This can be achieved by any build tool. I have used Gradle Build Tool. Click here to know How to install Gradle.
Step 5 – Add Selenium and JUnit5 dependencies to the Gradle project
/*
* This file was generated by the Gradle 'init' task.
*
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
java {
sourceCompatibility = 11
targetCompatibility = 11
}
dependencies {
// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
implementation 'com.google.guava:guava:30.1.1-jre'
implementation 'org.seleniumhq.selenium:selenium-java:4.4.0'
implementation 'io.github.bonigarcia:webdrivermanager:5.3.0'
}
application {
// Define the main class for the application.
mainClass = 'com.example.App'
}
tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform() {
}
testLogging {
events "passed", "skipped", "failed"
showStandardStreams = true
}
systemProperties System.properties
reports.html.setDestination(file("$projectDir/GradleReports"))
}
Step 6 – Create Pages and Test Code for the pages
We have used PageFactory model to build the tests. I have created a package named pages and created the page classes in that folder. Page class contains the locators of each web element present on that particular page along with the methods of performing actions using these web elements.
This is the BasePage that contains the PageFactory.initElements.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
public class BasePage {
public WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver,this);
}
}
Below is the code for LoginPage and HomePage
LoginPage
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPage extends BasePage{
public LoginPage(WebDriver driver) {
super(driver);
}
@FindBy(name = "username")
public WebElement userName;
@FindBy(name = "password")
public WebElement password;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
public WebElement missingUsernameErrorMessage;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
public WebElement missingPasswordErrorMessage;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
public WebElement login;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
public WebElement errorMessage;
public String getMissingUsernameText() {
return missingUsernameErrorMessage.getText();
}
public String getMissingPasswordText() {
return missingPasswordErrorMessage.getText();
}
public String getErrorMessage() {
return errorMessage.getText();
}
public void login(String strUserName, String strPassword) {
userName.sendKeys(strUserName);
password.sendKeys(strPassword);
login.click();
}
}
HomePage
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
}
@FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
public WebElement homePageUserName;
public String getHomePageText() {
return homePageUserName.getText();
}
}
Here, we have BaseTests Class also which contains the common methods needed by other test pages.
import java.time.Duration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class BaseTests {
public WebDriver driver;
public final static int TIMEOUT = 10;
@BeforeEach
public void setup() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://opensource-demo.orangehrmlive.com/");
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
}
@AfterEach
public void tearDown() {
driver.quit();
}
}
LoginPageTests
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Disabled;
public class LoginPageTests extends BaseTests{
@ParameterizedTest
@CsvSource({
"admin$$,admin123",
"Admin,admin123!!",
"admin123,Admin",
"%%%%%,$$$$$$"})
public void invalidCredentials(String username, String password) {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login(username, password);
// Verify Error Message
assertEquals("Invalid credentials",objLoginPage.getErrorMessage());
}
@Test
public void validLogin() {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login("Admin", "admin123");
HomePage objHomePage = new HomePage(driver);
// Verify Home Page
assertEquals("Employee Information",objHomePage.getHomePageText());
}
@Test
public void missingUsername() {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login("", "admin123");
// Verify Error Message
assertEquals("Invalid credentials",objLoginPage.getMissingUsernameText());
}
@Test @Disabled
public void missingPassword() {
LoginPage objLoginPage = new LoginPage(driver);
objLoginPage.login("admin", "");
// Verify Error Message
assertEquals("Invalid credentials",objLoginPage.getMissingPasswordText());
}
}
Step 7 – Run the tests from Command Line
Note:- As you can see, my project has two parts – GradleSeleniumJUnit5_Demo and app.
Go to the app project and run the tests, using the below command.
gradle clean test
The output of the above program is
Step 8 – Gradle Report generation
Once the test execution is finished, refresh the project. We will see a folder – GradleReports. This report is generated when the tests are executed through the command line.
This folder contains index.html.
Right-click on index.html and select open with Web Browser. This report shows the summary of all the tests executed. As you can see that Failed tests are selected (highlighted in blue), so the name of the test failed along with the class name is displayed here.
This report contains detailed information about the failed test, which is shown below.
This shows the list of all the tests – passed, failed, or ignored.
Assumptions is a collection of utility methods that support conditional test execution based on assumptions.
In direct contrast to failed assertions, failed assumptions do not result in a test failure; rather, a failed assumption results in a test being aborted.
Assumptions are typically used whenever it does not make sense to continue execution of a given test method — for example, if the test depends on something that does not exist in the current runtime environment.
Junit 5 comes with a subset of the assumption methods that JUnit 4 provides with Java 8 lambda expressions and method references. All JUnit Jupiter assumptions are static methods in the org.junit.jupiter.api.Assumptions class.
Assumptions.assumeTrue() – If the condition is true, then run the test, else aborting the test.
Assumptions.false() – If the condition is false, then run the test, else aborting the test.
Assumptions.assumingThat() – is much more flexible, If condition is true then executes, else do not abort test continue rest of code in test.
1. assumeTrue
The assumeTrue() method validates the given assumption to be true and if the assumption is true – the test proceed, otherwise, test execution is aborted.
int num1 = 4;
int num2=6;
int num3 = 24;
int num4=10;
@Test
void assumeTrueTest() {
System.setProperty("ENV", "TEST");
assumeTrue("TEST".equals(System.getProperty("ENV")));
// Since the condition is true rest of it will get executed
assertEquals((num1*num2),num3,"The product of "+num1+"and "+num2+"is equal to "+num3);
}
The output of the above program is
In the below example, assumeTrue() is false. So, the execution is skipped.
int num1 = 4;
int num2=6;
int num3 = 24;
int num4=10;
@Test
void assumeTrueTest1() {
System.setProperty("ENV", "TEST");
assumeTrue("QA".equals(System.getProperty("ENV")));
// Since the condition is true rest of it will not get executed
assertEquals((num1*num2),num3,"The product of "+num1+"and "+num2+"is equal to "+num3);
}
The output of the above program is
2. assumeFalse()
The assumeFalse() method validates the given assumption to false and if the assumption is false – test proceed, otherwise, test execution is aborted. In the below example, the test is false and we are using assumeFalse(), so the tests will be executed.
int num1 = 4;
int num2=6;
int num3 = 24;
int num4=10;
@Test
void assumeFalseTest1() {
System.setProperty("ENV", "TEST");
assumeFalse("DEV".equals(System.getProperty("ENV")));
// Since the condition is true rest of it will get executed
assertEquals((num1*num2),num3,"The product of "+num1+"and "+num2+"is equal to "+num3);
}
The output of the above program is
In the below example, the test is false and we are using assumeFalse(), so the tests will be executed.
@Test
void assumeFalseTest() {
System.setProperty("ENV", "TEST");
assumeFalse("TEST".equals(System.getProperty("ENV")));
// Since the condition is false rest of it will not get executed
assertEquals((num1*num2),num3,"The product of "+num1+"and "+num2+"is equal to "+num3);
}
The output of the above program is
3. assertThat()
This method executes the supplied Executable, but only if the supplied assumption is valid.
Unlike the other assumption methods, this method will not abort the test.
If the assumption is invalid, this method does nothing. If the assumption is valid and the executable throws an exception, it will be treated like a regular test failure. The thrown exception will be rethrown as is but masked as an unchecked exception.
int num1 = 4;
int num2=6;
int num3 = 24;
int num4=10;
int num5=8;
int num6=2;
@Test
void assumingThatTest() {
System.setProperty("ENV", "UAT");
assumingThat(
"UAT".equals(System.getProperty("ENV")),
() -> {
// Since the condition is true, this assertion will get executed
System.out.println("Assuming that executable executed");
assertEquals((num1+num2),num4,"The product of "+ num1 +" and "+ num2 +" is not equal to "+num4);
});
// Since the condition is false rest of it will get executed
System.out.println("Loop outside");
assertEquals((num5-num2),num6,"The difference of "+ num5 +" and "+num2+" is not equal to " + num6);
}
The output of the above program is
In the below example, the condition is false , so we skip the execution of that condition. But, we execute the rest of the code.
int num1 = 4;
int num2=6;
int num3 = 24;
int num4=10;
@Test
void assumingThatTest1() {
System.setProperty("ENV", "UAT");
assumingThat(
"DEV".equals(System.getProperty("ENV")),
() -> {
// Since the condition is false, this assertion will not get executed
System.out.println("Assuming that executable executed");
assertEquals((num1+num2),num4,"The sum of "+num1+"and "+num2+"is not equal to "+num4);
});
System.out.println("Loop outside");
assertEquals((num1*num2),num3,"The product of "+num1+"and "+num2+"is not equal to "+num3);
}
The output of the above program is
Difference between Assumption and Assertion
The main difference between the assertions and assumptions is –
The assumption is use to decide whether we want to execute a section or the rest of the test method or not and if the condition is false then the test is skipped.
Whereas if a condition in an assertion fails then it fails the test and something needs to be fixed.
JUnit5 enables us to execute a single test method multiple times with a different sets of data. This is called Parameterization. Parameterized Tests are declared just like regular @Test methods but use the @ParameterizedTest annotation.
This article shows you how to run a test multiple times with different arguments, so-called ‘Parameterized Tests’, let’s see the following ways to provide arguments to the test:
@ValueSource
@EnumSource
@MethodSource
@CsvSource
@CsvFileSource
@ArgumentsSource
We need to add junit-jupiter-params to support parameterized tests. In the case of Maven, add the dependency to POM.xml
Let us start with a simple example. The following example demonstrates a parameterized test that uses the @ValueSource annotation to specify an integer array as the source of arguments. The following @ParameterizedTest method will be invoked three times, with the values 5,6, and 0 respectively.
@ParameterizedTest
@ValueSource(ints = {5, 6, 0})
void test_int_arrays(int b) {
int a= 5;
int sum = a + b;
assertTrue(sum>8);
}
When executing the above-parameterized test method, each invocation will be reported separately.
The output of the above program is:
One of the limitations of value sources is that they only support these types:
short (with the shorts attribute)
byte (bytes attribute)
int (ints attribute)
long (longs attribute)
float (floats attribute)
double (doubles attribute)
char (chars attribute)
java.lang.String (strings attribute)
java.lang.Class (classes attribute)
Also, we can only pass one argument to the test method each time.
In the below example, an array of strings is passed as the argument to the Parameterized Test.
@ParameterizedTest(name = "#{index} - Run test with args={0}")
@ValueSource(strings = {"java", "python", "javascript","php"})
void test_string_arrays(String arg) {
assertTrue(arg.length() > 1);
}
The output of the above program is:
@NullSource
It provides a single null an argument to the annotated @ParameterizedTest method.
The parameterized test method result in seven invocations: 1 for null, 1 for the empty string, 4 for the explicit blank strings supplied via @ValueSource, and 1 non-blank string “a” supplied via @ValueSource.
The output of the above program is:
2. @EnumSource
@EnumSource provides a convenient way to use Enum constants.
The annotation provides an optional names attribute that lets you specify which constants shall be used, like in the following example. If omitted, all constants will be used.
The @EnumSource annotation also provides an optional mode attribute that enables fine-grained control over which constants are passed to the test method. For example, you can exclude names from the enum constant pool or specify regular expressions as in the following examples.
@MethodSource allows you to refer to one or more factory methods of the test class or external classes.
Factory methods within the test class must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS); whereas, factory methods in external classes must always be static. In addition, such factory methods must not accept any arguments.
If you only need a single parameter, you can return a Stream of instances of the parameter type as demonstrated in the following example.
@ParameterizedTest(name = "#{index} - Test with String : {0}")
@MethodSource("stringProvider")
void test_method_string(String arg) {
assertNotNull(arg);
}
// this need static
static Stream<String> stringProvider() {
return Stream.of("java", "junit5", null);
}
The output of the above program is
If you do not explicitly provide a factory method name via @MethodSource, JUnit Jupiter will search for a factory method that has the same name as the current @ParameterizedTest method by convention. This is demonstrated in the following example.
Streams for primitive types (DoubleStream, IntStream, and LongStream) are also supported as demonstrated by the following example.
@ParameterizedTest(name = "#{index} - Test with Int : {0}")
@MethodSource("rangeProvider")
void test_method_int(int arg) {
assertTrue(arg < 6);
}
static IntStream rangeProvider() {
return IntStream.range(0, 6);
}
The output of the above program is
If a parameterized test method declares multiple parameters, you need to return a collection, stream, or array of Arguments instances or object arrays as shown below.
@CsvSource allows you to express argument lists as comma-separated values (i.e., CSV String literals). Each string provided via the value attribute in @CsvSource represents a CSV record and results in one invocation of the parameterized test.
@CsvFileSource lets us use comma-separated value (CSV) files from the classpath or the local file system. Each record from a CSV file results in one invocation of the parameterized test. The first record may optionally be used to supply CSV headers.
If you would like the headers to be used in the display names, you can set the useHeadersInDisplayName attribute to true. The examples below demonstrate the use of useHeadersInDisplayName.
@ArgumentsSource can be used to specify a custom, reusable ArgumentsProvider. Note that an implementation of ArgumentsProvider must be declared as either a top-level class or as a static nested class.
The general practices say that automated tests should be able to run independently and with no specific order, as well as the result of the test should not depend on the results of previous tests. But there are situations where a specific order of test execution can be justified, especially in integration or end-to-end tests. The test methods don’t follow a specific order by default to execute the tests. The test cases need not necessarily execute in the order in which they have been written.
There are different ways or modes to set the order of execution for the test cases. This article shows how to control the JUnit 5 test execution order via the following MethodOrderer classes:
DisplayName – sorts test methods alphanumerically based on their display names
MethodName – sorts test methods alphanumerically based on their names and formal parameter lists
Alphanumeric – sorts test methods alphanumerically based on their names and formal parameter lists. This is deprecated from JUnit Version 5.7 onwards
OrderAnnotation – sorts test methods numerically based on values specified via the @Order annotation
Random – orders test methods pseudo-randomly and support the configuration of a custom seed
Custom Order – A custom ordering sequence can be implemented by the interface MethodOrderer and providing it as the argument to @TestMethodOrder.
It sorts test methods alphanumerically based on their display names. Test Method can be anything annotated with @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, or @TestTemplate.
@TestMethodOrder(MethodOrderer.DisplayName.class)
@TestMethodOrder is a type-level annotation that is used to configure a MethodOrderer for the test methods of the annotated test class or test interface.
MethodOrderer defines the API for ordering the test methods in a given test class.
Test Method – It is any method annotated with @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, or @TestTemplate.
DisplayName.class – MethodOrderer that sorts methods alphanumerically based on their names using String.compareTo(String). If two methods have the same name, String representations of their formal parameter lists will be used as a fallback for comparing the methods.
An example of sorting the tests based on their display names.
We can see that the test methods are sorted alphanumerically based on their display name starting from A to E. The output of the above program
2. MethodName
This annotation sorts methods alphanumerically based on their names using String.compareTo(String). If two methods have the same name, String representations of their formal parameter lists will be used as a fallback for comparing the methods.
This sorts test method numerically based on values specified via the @Order annotation. Any methods that are assigned the same order value will be sorted arbitrarily adjacent to each other. When any method is not annotated with @Order, it will be assigned the default order value, which will effectively cause them to appear at the end of the sorted list.
The previous tutorial explains to configure Junit in IntelliJ and run the tests as JUnit Tests. This tutorial shows the steps to run the tests through command line. We can ask, why we need to run the tests through command line?? There are many reasons, one of the reason is to achieve CI/CD. To run the tests in pipeline, they need to be run through command line. Another reason is that we don’t need to open the IDE to run the tests. Third reason is that many reports are only generated (Serenity, Cucumber), if the tests run through command line.
Below is a JUnit5 test.
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class Demo {
WebDriver driver;
@BeforeEach
public void setUp() {
WebDriverManager.chromedriver().setup();
ChromeOptions chromeOptions = new ChromeOptions();
driver = new ChromeDriver(chromeOptions);
driver.manage().window().fullscreen();
}
@Test
public void Junit5Test() {
driver.get("http://automationpractice.com/index.php");
System.out.println("Title of Page :" + driver.getTitle());
System.out.println("Page URL : " + driver.getCurrentUrl());
Assertions.assertEquals("My Store",driver.getTitle());
}
@AfterEach
public void tearDown() {
driver.close();
}
}
Let us see what happens when we try to run the JUnit tests through Command Line. This command is used to run the tests present in Demo class.
mvn clean test -Dtest=Demo
The output generated by the test is shown below
This shows that surefire-plugin is need to be add to the project to run t he tests successfully through command line.
JUnit5 contains the assertions available as in JUnit 4 Assertions as well there are a few additional new asserts too. In this post, let’s discuss each new assertion in JUnit5 works in detail with examples.
1. assertIterableEquals
The assertIterableEquals() asserts that the expected and the actual iterables are deeply equal. In order to be equal, both iterable must return equal elements in the same order and it isn’t required that the two iterables are of the same type in order to be equal.
Example 1 – In this example, the number of elements as well as the sequence of elements is in the same order in both Iterables. It is not mandatory to have Iterables of the same type, so we can see as one of the Iterable is ArrayList whereas another Iteratble is of type LinkedList.
As both Iterables do not have same number of elements, so the Assertion has failed.
Note:- There are no assertions like assertNotIterableEquals() or assertIterableNotEquals().
2. assertLinesMatch
This Assertion asserts that the expected list of Strings matches the actual list of String. This method differs from other assertions that effectively only check String.equals(Object), in that it uses the following staged matching algorithm: For each pair of expected and actual lines do a) check if expected.equals(actual) – if yes, continue with next pair b) otherwise treat expected as a regular expression and check via String.matches(String) – if yes, continue with the next pair c) otherwise check if an expected line is a fast-forward marker, if yes apply to fast-forward actual lines accordingly (see below) and goto 1.
Example 1 – In the below example, expected has a regular expression that matches with the elements of actual.
When we want to assert that execution of the supplied executable completes before the given timeout, we can use assertTimeout().
Example 1 – In the below example, assertTimeout() is 2 sec, which means the assertion should be completed within 2 secs. We are waiting for 1 sec and then perform the assertion.
@Test
void assertTimeoutPositive() {
int a = 4;
int b= 5;
assertTimeout(
ofSeconds(2),
() -> {
// code that requires less then 2 seconds to execute
Thread.sleep(1000);
}
);
assertEquals(9, (a + b));
}
As the assertion is within the specified time of assertTimeout(), the timeout assertion passes and the test passes.
Example 2 – In the below example, assertTimeout() is 2 sec whereas are waiting for 5 sec and then performing the assertion.
@Test
void assertTimeoutNegative() {
int a = 4;
int b= 5;
assertTimeout(
ofSeconds(2),
() -> {
// code that requires less then 2 seconds to execute
Thread.sleep(5000);
}
);
assertEquals(9, (a + b));
}
As the assertion is outside the specified time of assertTimeout(), so the test fails. The assertion fails with an error message similar to: “execution exceeded timeout of 2000 ms by 3010 ms”.
Example 3 – In the below example, the assertion is mentioned just after
The executable will be executed in the same thread as that of the calling code. Consequently, execution of the executable will not be preemptively aborted if the timeout is exceeded.
@Test
void assertTimeoutNegative1() {
int a = 4;
int b= 5;
assertTimeout(
ofSeconds(2),
() -> {
// code that requires less then 2 seconds to execute
Thread.sleep(5000);
assertEquals(10, (a + b));
}
);
}
This shows that the assertion assertEquals() is still executed after the timeout also.
5. assertTimeoutPreemptively()
This assertion works just like assertTimeout(). When we want to assert that the execution of the supplied executable completes before the given timeout, we can use assertTimeoutPreemptively(). The only difference is that here the executable will be executed in a different thread than that of the calling code, whereas in assertTimeout() the executable will be executed in the same thread as that of the calling code. Furthermore, execution of the executable will be preemptively aborted if the timeout is exceeded here as contrary to assertTimeout() where the executable will not be preemptively aborted.
@Test
void assertPreemptiveTimeoutNegative() {
int a = 4;
int b= 5;
assertTimeoutPreemptively(
ofSeconds(2),
() -> {
// code that requires less then 2 seconds to execute
Thread.sleep(5000);
assertEquals(9, (a + b));
}
);
}
In this post, We saw that JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java 8 lambdas. All JUnit Jupiter assertions are static methods in the org.junit.jupiter.api.Assertions class.