How to run parameterized Selenium test using JUnit5

HOME

The previous tutorial has shown the various parameterized tests in JUnit5. This tutorial shows how to run a Selenium test multiple times with a different set of data. This helps to reduce the duplication of code. This is a very common scenario in any testing. Imagine, we want to test the requirement for a login page that uses a username and password to log in to the application. Username and password must satisfy some conditions like username can be only alphabets and no numeric and special characters. There could be multiple sets of data that can be used to test this requirement.

Prerequisite:

  1. Selenium – 4.21.0
  2. Maven – 3.9.6
  3. Java 17
  4. JUnit Jupiter Engine – 5.11.0-M2
  5. JUnit Jupiter API – 5.11.0-M2

JUnit5 provides a lot of ways to parameterize a test – @ValueSource, @EnumSource, @MethodSource, @CsvSource, @CsvFileSource, and @ArgumentsSource.

Let us see an example where the test is not parameterized. In the below example, we want to verify the different error messages generated by passing incorrect values to username and password.

This is the base class – Login which contains the test method that uses a different set of test data.

package com.example.parameterized;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class LoginPage {

    WebDriver driver ;

    @FindBy(name="username")
    WebElement username;

    @FindBy(name="password")
    WebElement password;

    @FindBy(xpath="//*[@class='oxd-form']/div[3]/button")
    WebElement loginButton;

    @FindBy(xpath="//*[@class='orangehrm-login-error']/div[1]/div[1]/p")
    WebElement actualErrorMessage;


    public LoginPage(WebDriver driver) {

        this.driver = driver;

        // This initElements method will create all WebElements
        PageFactory.initElements(driver, this);
    }

    public void setUserName(String strUserName) {
        username.sendKeys(strUserName);
    }

    // Set password in password textbox
    public void setPassword(String strPassword) {
        password.sendKeys(strPassword);
    }

    // Click on login button
    public void clickLogin() {
        loginButton.click();
    }

    // Get the error message
    public String getErrorMessage() {
        return actualErrorMessage.getText();
    }

    public void login(String strUserName, String strPasword) {

        // Fill user name
        this.setUserName(strUserName);

        // Fill password
        this.setPassword(strPasword);

        // Click Login button
        this.clickLogin();
    }

}

The below example shows 4 tests using a common test with 4 different sets of data.

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class NonParameterizedLoginTest {

    WebDriver driver;
    LoginPage login;

    @BeforeEach
    void setUp() {

        ChromeOptions chromeOptions = new ChromeOptions();
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().maximize();
        driver.get("https://opensource-demo.orangehrmlive.com/");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

    @Test
    void invalidCredentials1() {

        login = new LoginPage(driver);
        login.login("Admin","Admin");
        String actualErrorMessage = login.getErrorMessage();
        assertEquals("Invalid credentials", actualErrorMessage);

    }

    @Test
    void invalidCredentials2() {

        login = new LoginPage(driver);
        login.login("admin","Admin");
        String actualErrorMessage = login.getErrorMessage();
        assertEquals("Invalid credentials", actualErrorMessage);

    }

    @Test
    void invalidCredentials3() {

        login = new LoginPage(driver);
        login.login("Admin","123");
        String actualErrorMessage = login.getErrorMessage();
        assertEquals("Invalid credentials", actualErrorMessage);

    }

    @Test
    void invalidCredentials4() {

        login = new LoginPage(driver);
        login.login("admin123","3456admin");
        String actualErrorMessage = login.getErrorMessage();
        assertEquals("Invalid credentials", actualErrorMessage);

    }

    @AfterEach
    void tearDown() {
        if (driver != null) {
            driver.close();
        }
    }

}

We can see that the same method is called multiple times. This is a duplication of code. The output of the above program is

Now, we will parametrize the same test. To do so, we need to add a dependency to the POM.xml.

<project xmlns="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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>JUnit5_Examples</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>JUnit5_Examples</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <selenium.version>4.21.0</selenium.version>
    <junit.jupiter.engine.version>5.11.0-M2</junit.jupiter.engine.version>
    <junit.jupiter.api.version>5.11.0-M2</junit.jupiter.api.version>
    <junit.jupiter.params.version>5.11.0-M2</junit.jupiter.params.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>

    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit.jupiter.engine.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit.jupiter.api.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>${junit.jupiter.params.version}</version>
      <scope>test</scope>
    </dependency>

  </dependencies>

  <build>
    <plugins>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>

        <dependencies>
          <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.engine.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

</project>

There are multiple ways to parameterize the test. To start with:

  1. Replace @Test annotation with @ParameterizedTest annotation provided by the JUnit5 framework.
  2. Add parameters to the loginTest() method. In this example, we will add a username and a password parameter.
  3. Add the parameters source. In this example, we will use the @CsvFileSource annotation.

To know all the different types of parameterization methods, please refer to this tutorial. This tutorial will show the 2 most common ways to parameterize tests in JUnit5.

1.@CsvSource

@CsvSource allows us 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. An empty, quoted value (”) results in an empty String. This can be seen in the below example.

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ParameterizedSourceTest {

    WebDriver driver;

    LoginPage loginPage;

    @BeforeEach
    void setUp() {

        ChromeOptions chromeOptions = new ChromeOptions();
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().maximize();
        driver.get("https://opensource-demo.orangehrmlive.com/");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));

    }

    @ParameterizedTest
    @CsvSource({
            "admin123,admin123,Invalid credentials",
            "admin,admin12,Invalid credentials",
            "Admin,1234,Invalid credentials",
            "12345,%^$£56,Invalid credentials"
    })

    void invalidCredentials1(String username, String password, String errorMessage) {

        loginPage = new LoginPage(driver);
        loginPage.login(username,password);
        String actualErrorMessage = loginPage.getErrorMessage();
        assertEquals(errorMessage, actualErrorMessage);

    }

    @AfterEach
    void tearDown() {
        driver.close();
    }
}

The output of the above program is

2. @CsvFileSource

@CsvFileSource lets us use comma-separated value (CSV) files from the classpath or the local file system.

We can see in the below example, that we have skipped the first line from the credentials.csv file as it is the heading of the file. invalidCredentials() method got 4 different set of the test data from CSV file using parameterization. JUnit5 ignores the headers via the numLinesToSkip attribute.

In this example, will retrieve the data from CSV. This CSV file is placed under src/test/resources. Below is the example of the credentials.csv file.

In @CsvFileSource, an empty, quoted value (“”) results in an empty String in JUnit5.

package com.example.parameterized;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class ParameterizedFileTest {

    WebDriver driver;

    LoginPage loginPage;

    @BeforeEach
    void setUp() {

        ChromeOptions chromeOptions = new ChromeOptions();
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().maximize();
        driver.get("https://opensource-demo.orangehrmlive.com/");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));

    }

    @ParameterizedTest
    @CsvFileSource(files = "src/test/resources/credentials.csv", numLinesToSkip = 1)
    void invalidCredentials1(String username, String password, String errorMessage) {

        loginPage = new LoginPage(driver);
        loginPage.login(username,password);
        String actualErrorMessage = loginPage.getErrorMessage();
        assertEquals(errorMessage, actualErrorMessage);

    }

    @AfterEach
    void tearDown() {
        driver.close();
    }
}

The result of the above program is

Congratulations!! We have seen how Selenium tests are parameterized in JUnit5. Happy Learning.

How to Retry Test in JUnit5 – @RepeatedTest

HOME

In JUnit5, JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with @RepeatedTest. We can specify the repetition frequency as a parameter to the @RepeatedTest annotation.

When do we use the Repeated Test?

Imagine, we are testing an online shopping website. In the process of placing an order, we need to pay for the product. But the payment gateway is a third-party service, and we cannot control the connectivity between our website and the payment gateway. We know that clicking on the ‘Payment’ link sometime shows “Exception: Page cannot be displayed”. This is an intermittent issue. So, we don’t want to fail the test if this payment link does not work. We can configure it to click this payment link multiple times, before marking the test case failed. Here comes the Repeated Test in the picture.

A few points to keep in mind for @RepeatedTest are as follows:

  1. The methods annotated with @RepeatedTest cannot be static, otherwise, the test cannot be found.
  2. The methods annotated with @RepeatedTest cannot be private, otherwise, the test cannot be found.
  3. The return type of the method annotated with @RepeatedTest must be void only, otherwise, the test cannot be found.

The below example will run the test 5 times.

 @DisplayName("Addition")
 @RepeatedTest(3)
 void repeatTest(){
    int a = 4;
    int b = 6;
    assertEquals(10, a+b,"Incorrect sum of numbers");
 }

The output of the above test:

Each invocation of a repeated test behaves like the execution of a regular @Test method, with full support for the same lifecycle callbacks and extensions.

It means that @BeforeEach and @AfterEach annotated lifecycle methods will be invoked for each invocation of the test.

@BeforeEach annotation is used to signal that the annotated method should be executed before each invocation of the @Test@RepeatedTest@ParameterizedTest, or @TestFactory method in the current class. This is the replacement of the @Before Method in JUnit4.

TestInfo is used to inject information about the current test or container into @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll methods.
If a method parameter is of type TestInfo, JUnit will supply an instance of TestInfo corresponding to the current test or container as the value for the parameter.

RepetitionInfo is used to inject information about the current repetition of a repeated test into the @RepeatedTest, @BeforeEach, and @AfterEach methods.
If a method parameter is of type RepetitionInfo, JUnit will supply an instance of RepetitionInfo corresponding to the current repeated test as the value for the parameter.

In the below example, @BeforeEach will get executed before each repetition of each repeated test. By having the TestInfo and RepetitionInfo injected into the method, we see that it’s possible to obtain information about the currently executing repeated test.

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

public class RepeatCycleDemo {

    @BeforeEach
    void init(TestInfo testInfo, RepetitionInfo repetitionInfo) {
      System.out.println("Before Each init() method called");
      int currentRepetition = repetitionInfo.getCurrentRepetition();
      int totalRepetitions = repetitionInfo.getTotalRepetitions();
      String methodName = testInfo.getTestMethod().get().getName();
      System.out.println(String.format("About to execute repetition %d of %d for %s", currentRepetition, totalRepetitions, methodName));
     }

    @RepeatedTest(3)
    void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
      int a = 4;
      int b = 6;
      assertEquals(10, a+b, repetitionInfo.getTotalRepetitions());
    }

    @AfterEach
    public void cleanUpEach(){
      System.out.println("=================After Each cleanUpEach() method called =================");
    }
}

The output of the above test:

Custom Display Name

In addition to specifying the number of repetitions, a custom display name can be configured for each repetition via the name attribute of the @RepeatedTest annotation.

The display name can be a pattern composed of a combination of static text and dynamic placeholders. The following placeholders are currently supported.

  1. {displayName}: display name of the @RepeatedTest method
  2. {currentRepetition}: the current repetition count
  3. {totalRepetitions}: the total number of repetitions

    @BeforeEach
    void init(TestInfo testInfo, RepetitionInfo repetitionInfo) {
        System.out.println("Before Each init() method called");
        int currentRepetition = repetitionInfo.getCurrentRepetition();
        int totalRepetitions = repetitionInfo.getTotalRepetitions();
        String methodName = testInfo.getTestMethod().get().getName();
        System.out.println(String.format("About to execute repetition %d of %d for %s", //
                currentRepetition, totalRepetitions, methodName));
    }

   //Custom Display  
    @RepeatedTest(value = 2, name = "{displayName} {currentRepetition}/{totalRepetitions}")
    @DisplayName("Repeat JUnit5 Test")
    void customDisplayName(TestInfo testInfo) {
        assertEquals("Repeat JUnit5 Test 1/2", testInfo.getDisplayName());
    }

The output of the above test:

The default display name for a given repetition is generated based on the following pattern: “repetition {currentRepetition} of {totalRepetitions}”. Thus, the display names for individual repetitions of the previous repeatedTest() example would be repetition 1 of 10, and repetition 2 of 10.

We can use one of two predefined formats for displaying the name – LONG_DISPLAY_NAME and SHORT_DISPLAY_NAME. The latter is the default format if none is specified.

  1. RepeatedTest.LONG_DISPLAY_NAME – {displayName} :: repetition {currentRepetition} of {totalRepetitions}
  2. RepeatedTest.SHORT_DISPLAY_NAME – repetition {currentRepetition} of {totalRepetitions}

Below is an example of SHORT_DISPLAY_NAME

    @RepeatedTest(value = 3, name = RepeatedTest.SHORT_DISPLAY_NAME)
    @DisplayName("Multiplication")
    void customDisplayNameWithShortPattern() {
        assertEquals(8, 6*5);
 }

In this case, the name is displayed as Multiplication repetition 1 of 3, repetition 2 of 3, and soon.

The output of the above test:

Below is an example of LONG_DISPLAY_NAME

  @RepeatedTest(value = 3, name = RepeatedTest.LONG_DISPLAY_NAME)
    @DisplayName("Addition")
    void customDisplayNameWithLongPattern(TestInfo testInfo) {
        System.out.println("Display Name :"+ testInfo.getDisplayName());
        System.out.println("Test Class Name :"+ testInfo.getTestClass());
        System.out.println("Test Method :"+ testInfo.getTestMethod());
        assertEquals(8, 3+7);
    }

The output of the above test:

As we can see in the example, we have used @DisplayName(“Addition”), but as it is name = RepeatedTest.LONG_DISPLAY_NAME, so the name of the tests are now Addition :: repetition 1 of 3, Addition :: repetition 2 of 3 and soon.

Congratulations. We are able to execute the tests multiple times by using the @RepeatedTest annotation. Happy Learning!!

How to disable tests in JUnit5 – @Disabled

HOME

JUnit5 also provides the support to exclude/disable the tests. The @Disabled annotation in JUnit5 is used to exclude the test methods from the test suite. This annotation can be applied over a test class as well as over individual test methods. This annotation accepts only one optional parameter where we can mention the reason to skip the tests. @Disabled annotation can be used without providing any reason but its always good to provide a reason why this particular test case has been disabled, or issue tracker id for better understanding.

1.Disable Test Methods

In the below example, I have annotated 2 test methods out of 5 test methods as @Disabled with a parameter which specify the reason for disabling the test that means these 2 test methods should not be executed.

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class DisabledTestsDemo {

    WebDriver driver;

    @BeforeEach
    public void setUp() {

        ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.addArguments("--start-maximized");
        driver = new ChromeDriver(chromeOptions);
        driver.get("https://duckduckgo.com/");

    }

    @Disabled("This test is blocked till bug 1290 is fixed")
    @Test
    void verifyBrowserText() {
        boolean displayed = driver.findElement(By.xpath("//section[@class='homepage-cta-section_ctaSection__o_ioD']/h2")).isDisplayed();
        assertTrue(displayed);

    }

    @Test
    void verifyPageTitle() {

        String pageTitle = driver.getTitle();
        assertEquals("DuckDuckGo — Privacy, simplified.", pageTitle);

    }

    @Test
    void verifyDownloadBrowserButton() {

        boolean downloadBrowserBtn = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/a/span")).isDisplayed();
        assertTrue(downloadBrowserBtn);
    }

    @Test
    void displaySearchBox() {

        boolean searchBoxDisplayed = driver.findElement(By.xpath("//*[@id=\"searchbox_input\"]")).isEnabled();
        assertTrue(searchBoxDisplayed);
    }

    @Disabled("This test is not applicable for Sprint 14")
    @Test
    void verifyDefaultSearchButtonText() {

        String defaultSearchBtnText = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/h2")).getText();
        assertEquals("Free. Fast. Private. Get our browser on all your devices.",(defaultSearchBtnText));
    }

    @AfterEach
    public void tearDown() {
        driver.close();
    }
}

The output of the above test shows, the 2 tests that are annotated with @Disabled are not executed.

2. Disable Test Class

When we annotate a class as @Disabled, then all the test methods present within that test class will not be executed.

In the below example, there are 2 test classes – Demo and DisabledTestsDemo. Demo class contains 1 test method whereas DisabledTestsDemo contains 5 test methods. I have annotated DisabledTestsDemo class as @Disabled which means all 5 tests present within it will not be executed.

In the below example, there is a base class that contains the initialization of webDriver as well as closing of the same.

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class Base {

    static WebDriver driver=null;

    @BeforeEach
    public void setUp() {

        ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.addArguments("--start-maximized");
        driver = new ChromeDriver(chromeOptions);
        driver.get("https://duckduckgo.com/");

    }

    @AfterEach
    public void tearDown() {
        driver.close();
    }
}

Class 1 – Demo

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class NonDisabledClass extends Base {

    @Test
    void verifyPageTitle() {

        String pageTitle = driver.getTitle();
        assertEquals("DuckDuckGo — Privacy, simplified.", pageTitle);

    }
}

Class 2 – DisabledTestsDemo

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@Disabled
public class DisabledClassDemo extends Base {

    @Test
    void verifyBrowserText() {
        boolean displayed = driver.findElement(By.xpath("//section[@class='homepage-cta-section_ctaSection__o_ioD']/h2")).isDisplayed();
        assertTrue(displayed);

    }

    @Test
    void verifyDownloadBrowserButton() {

        boolean downloadBrowserBtn = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/a/span")).isDisplayed();
        assertTrue(downloadBrowserBtn);
    }

    @Test
    void displaySearchBox() {

        boolean searchBoxDisplayed = driver.findElement(By.xpath("//*[@id=\"searchbox_input\"]")).isEnabled();
        assertTrue(searchBoxDisplayed);
    }

    @Test
    void verifyDefaultSearchButtonText() {

        String defaultSearchBtnText = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/h2")).getText();
        assertEquals("Free. Fast. Private. Get our browser on all your devices.",(defaultSearchBtnText));
    }
}

The output of the above test shows, all the test methods present in the class that is annotated with @Disabled are not executed.

Congratulations. We are able to understand the usage of @Disabled annotation in JUnit5. Happy Learning!!

Difference between JUnit4 and JUnit5

HOME

In this article, we’ll see an overview of the differences between the two versions of the library.

1. Architecture

JUnit 4 has everything bundled into a single jar file whereas JUnit 5 is composed of 3 sub-projects i.e. JUnit Platform, JUnit Jupiter, and JUnit Vintage.

JUnit4

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

JUnit Platform: It defines the TestEngine API for developing new testing frameworks that run on the platform.
JUnit Jupiter: It has all new JUnit annotations and TestEngine implementation to run tests written with these annotations.
JUnit Vintage: To support running JUnit 3 and JUnit 4 written tests on the JUnit 5 platform.

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.9.0-M1</version>
    <scope>test</scope>
</dependency>

2. JDK Version

JUnit 4 requires Java 5 (or higher) whereas JUnit 5 requires Java 8 (or higher).

3. Imports

JUnit 5 uses the org.JUnit package for its annotations and classes whereas JUnit 5 uses the new org.JUnit.jupiter package for its annotations and classes. For example, org.JUnit.Test becomes org.JUnit.jupiter.api.Test.
@Before annotation of JUnit4 is renamed to @BeforeEach in JUnit5
@After annotation of JUnit4 is renamed to @AfterEach in JUnit5
@BeforeClass annotation of JUnit4 is renamed to @BeforeAll in JUnit5
@AfterClass annotation of JUnit4 is renamed to @AfterAll in JUnit5

4. Assertions

JUnit 5 assertions are now in org.JUnit.jupiter.api.Assertions whereas JUnit4 assertions are in org.JUnit.Assert. Most of the common assertions, like assertEquals() and assertNotNull() look the same as before, but there are a few key differences:

  • The error message is now the last argument, for example, assertEquals(“my message”, 1, 2) would be assertEquals(1, 2, “my message”)
  • Most assertions now accept a lambda that constructs the error message, which is only called when the assertion fails.
    @Test
    void nullNegative() {
        String str = "Summer";

        Assertions.assertNull(str, () -> "The string should be null");
    }

The output of the above program is

  • assertTimeout() and assertTimeoutPreemptively() have replaced the @Timeout annotation (note that there is a @Timeout annotation in JUnit 5, but it works differently than JUnit 4).
  • There are several new assertions in JUnit5- assertAll(), assertIterableEquals(), assertLinesMatch(), assertThrows() and assertDoesNotThrow(). To know more about assertions in JUnit5, please refer to this tutorial – JUnit5 Assertions Example

5. Assumptions

In Junit 4, org.junit.Assume contains methods for stating assumptions about the conditions in which a test is meaningful. It has the following five methods:

  • assumeFalse()
  • assumeNoException()
  • assumeNotNull()
  • assumeThat()
  • assumeTrue()

JUnit5 has the following three methods:

  • assumeFalse()
  • assumingThat​()
  • assumeTrue()

Below is an example of assumeThat() annotation in JUnit5.

    @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);
                });
        
        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

6. Conditional Test Execution

In JUnit4, @Ignore is used to skip the execution of a test whereas @Disabled or one of the other built-in execution conditions is used to skip the execution of the test in JUnit5. To know more about skipping the tests in JUnit5, please refer to this tutorial – How to disable tests in JUnit5 – @Disabled.

Below is an example of @Disabled in JUnit5.

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.junit.jupiter.api.Assertions.*;
 
class DisabledTestsDemo {
 
    WebDriver driver;
 
    @BeforeEach
    public void setUp() {
         
        WebDriverManager.chromedriver().setup();
        ChromeOptions chromeOptions = new ChromeOptions();
        driver = new ChromeDriver(chromeOptions);
        driver.manage().window().fullscreen();
        driver.get("http://automationpractice.com/index.php");
 
    }
 
    @Disabled("This test is not applicable for Sprint 14")
    @Test
    void verifyPopularLink() {
 
        boolean displayed = driver.findElement(By.xpath("//*[@id='home-page-tabs']/li[1]/a")).isDisplayed();
        assertTrue(displayed);
    }
 
    @Test
    void verifyContactNumber() {
 
        String contactDetail = driver.findElement(By.xpath("//span[@class='shop-phone']/strong")).getText();
        assertEquals("0123-456-789", contactDetail);
    }
 
    @Disabled("This test is blocked till bug 1290 is fixed")
    @Test
    void verifyWomenLink() {
 
        boolean enabled = driver.findElement(By.xpath("//*[@id='block_top_menu']/ul/li[1]/a")).isEnabled();
        assertTrue(enabled);
    }
 
    @AfterEach
    public void tearDown() {
        driver.close();
    }
}

The output of the above program is

JUnit 5 provides the ExecutionCondition extension API to enable or disable a test or container (test class) conditionally. This is like using @Disabled on a test but it can define custom conditions. There are multiple built-in conditions, such as:

  • @EnabledOnOs and @DisabledOnOs: Enables a test only on specified operating systems.
  • @EnabledOnJre and @DisabledOnJre: Specifies the test should be enabled or disabled for specific versions of Java.
  • @EnabledIfSystemProperty: Enables a test based on the value of a JVM system property.
  • @EnabledIf: Uses scripted logic to enable a test if scripted conditions are met.

7. Extending JUnit

@RunWith no longer exists; superseded by @ExtendWith in JUnit5.

In JUnit 4, customizing the framework generally meant using a @RunWith annotation to specify a custom runner. Using multiple runners was problematic, and usually required chaining or using a @Rule. This has been simplified and improved in JUnit 5 using extensions.

import net.serenitybdd.core.Serenity;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import net.thucydides.core.annotations.Managed;
import net.thucydides.core.annotations.Steps;
import net.thucydides.core.annotations.Title;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.WebDriver;
import static org.assertj.core.api.Assertions.assertThat;
 
 @ExtendWith(SerenityJUnit5Extension.class)
 class ApplicationLoginJUnit5Tests {
 
        @Managed
        WebDriver driver;
 
        @Steps
        NavigateAction navigateAction;
 
        @Steps
        StepLoginPage loginPage;
 
        @Test
        @Title("Login to application with valid credentials navigates to DashBoard page")
 
         void successfulLogin() {
 
            navigateAction.toTheHomePage();
 
            // When
            loginPage.inputUserName("Admin");
            loginPage.inputPassword("admin123");
            loginPage.clickLogin();
 
            // Then
            Serenity.reportThat("Passing valid credentials navigates to DashBoard page",
                    () -> assertThat(dashboardPage.getHeading()).isEqualToIgnoringCase("DashBoard"));
        }
    }

8. Non-public Test Methods are Allowed

JUnit 5 test classes and test methods are not required to be public. We can now make them package protected.
JUnit internally uses reflection to find test classes and test methods. Reflection can discover them even if they have limited visibility, so there is no need for them to be public.

9. Repeat Tests

JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with @RepeatedTest and specifying the total number of repetitions desired. To know more about RepestedTest, please refer to this tutorial – How to Retry Test in JUnit5 – @RepeatedTest

Below is the example of @RepeatedTest in JUnit5.

    @RepeatedTest(3)
    void repeatedTestWithRepetitionInfo1(RepetitionInfo repetitionInfo) {
        assertEquals(3, repetitionInfo.getTotalRepetitions());
    }

The output of the above program is

10. Parameterized Tests

Test parameterization existed in JUnit 4 with built-in libraries like JUnit4Parameterized or third-party libraries like JUnitParams. In JUnit 5, parameterized tests are completely built-in and adopt some of the best features from JUnit4Parameterized and JUnitParams. To know more about the parameterized tests in JUnit5, please refer to this tutorial – How to parameterized Tests in JUnit5.

Below is an example of parameterized Test in JUnit5.

public class CSVParameterizedTest {

    @ParameterizedTest
    @CsvSource({
            "java,      4",
            "javascript,   7",
            "python,    6",
            "HTML,    4",
    })


    void test(String str, int length) {
        assertEquals(length, str.length());
    }
}

The output of the above program is

Congratulations. We have gone through the differences between JUnit4 and JUnit5. Happy Learning!!

Integration of Cucumber7 with Selenium and JUnit5

Last Updated On

HOME

I have created a lot of tutorials on creating Test Frameworks by integrating JUnit4 with Selenium, Cucumber, Serenity, Rest API, Springboot. This tutorial explain the steps to Integrate Cucumber7 with JUnit5.

JUnit 5 is composed of several different modules from three different sub-projects.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

We can use the JUnit Platform to execute Cucumber scenarios.

Add the cucumber-junit-platform-engine dependency to your pom.xml:

<dependency>
   <groupId>io.cucumber</groupId>
   <artifactId>cucumber-junit-platform-engine</artifactId>
   <version>${cucumber.version}</version>
   <scope>test</scope>
</dependency>

This will allow IntelliJ IDEA, Eclipse, Maven, Gradle, etc, to discover, select and execute Cucumber scenarios.

Table of Contents

Prerequisite

  1. Java Version 17 installed
  2. Eclipse or IntelliJ installed
  3. Maven or Gradle installed and setup
  4. Cucumber Eclipse Plugin installed

Project Structure

Implementation Steps

Step 1- Download and Install Java

Cucumber and Selenium need 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, which is needed to write Java code. Click here to know How to install Eclipse.

Step 3 – Setup Maven

To build a test framework, we need to add a number of dependencies to the project. It is a very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool that is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.

Step 4 – Install Cucumber Eclipse Plugin (Only for Eclipse IDE)

The Cucumber Eclipse plugin is a plugin that allows eclipse to understand the Gherkin syntax. The Cucumber Eclipse Plugin highlights the keywords present in Feature File. Click here to know more – Install Cucumber Eclipse Plugin.

Step 5 – Create a new Maven Project

Click here to know How to create a Maven project

Below is the Maven project structure. Here,

Group Id – com.example
Artifact Id – Cucumber7JUnit5Demo
Version – 0.0.1-SNAPSHOT
Package – com. example. Cucumber7JUnit5Demo

Step 6 – Add Maven dependencies to the POM

Add the dependencies to the POM.xml.

<project xmlns="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>com.example</groupId>
  <artifactId>Cucumber7JUnit5Demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<cucumber.version>7.14.0</cucumber.version>
		<selenium.version>4.15.0</selenium.version>
		<webdrivermanager.version>5.5.3</webdrivermanager.version>
		<junit.jupiter.version>5.10.1</junit.jupiter.version>
		<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
		<maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
		<maven.compiler.source.version>17</maven.compiler.source.version>
		<maven.compiler.target.version>17</maven.compiler.target.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.cucumber</groupId>
				<artifactId>cucumber-bom</artifactId>
				<version>${cucumber.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.junit</groupId>
				<artifactId>junit-bom</artifactId>
				<version>${junit.jupiter.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>

		<dependency>
			<groupId>io.cucumber</groupId>
			<artifactId>cucumber-java</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>io.cucumber</groupId>
			<artifactId>cucumber-junit-platform-engine</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- JUnit Platform -->
		<dependency>
			<groupId>org.junit.platform</groupId>
			<artifactId>junit-platform-suite</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- Selenium -->
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>${selenium.version}</version>
		</dependency>

		<!-- Web Driver Manager -->
		<dependency>
			<groupId>io.github.bonigarcia</groupId>
			<artifactId>webdrivermanager</artifactId>
			<version>${webdrivermanager.version}</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>${maven.compiler.plugin.version}</version>
				<configuration>
					<source>${maven.compiler.source.version}</source>
					<target>${maven.compiler.target.version}</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>${maven.surefire.plugin.version}</version>
				<dependencies>
					<dependency>
						<groupId>org.junit.jupiter</groupId>
						<artifactId>junit-jupiter-engine</artifactId>
						<version>${junit.jupiter.version}</version>
					</dependency>
				</dependencies>
			</plugin>

		</plugins>
	</build>
</project>

Step 7 – Create a feature file in src/test/resources

Below is a sample feature file. Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. The test scenarios are written in Gherkins language.

@LoginPage
Feature: Login to HRM Application

Background:
    Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"

   @ValidCredentials
   Scenario: Login with valid credentials

    When User enters username as "Admin" and password as "admin123"
    Then User should be able to login successfully and new page open
    
   @InvalidCredentials
   Scenario Outline: Login with invalid credentials
     
    When User enters username as "<username>" and password as "<password>"
    Then User should be able to see error message "<errorMessage>"
    
  Examples:
  | username   | password    | errorMessage                      |
  | Admin        | admin12$$  | Invalid credentials               |
  | admin$$     | admin123    | Invalid credentials               |
  | abc123        | xyz$$           | Invalid credentials               |
  
    
  @FaceBookLink
  Scenario: Verify FaceBook Icon on Login Page
     
    Then User should be able to see FaceBook Icon
    
  @LinkedInLink
  Scenario: Verify LinkedIn Icon on Login Page
     
    Then User should be able to see LinkedIn Icon  
    

@ForgetPassword
Feature: Login to ForgotPassword Page

  Background:
    Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"

  @ForgetPasswordLink
  Scenario: Verify ForgetPassword link on Login Page

    When User clicks on Forgot your Password Link
    Then User should navigate to a new page

Step 8 – Create cucumber.properties file in src/test/resources

We need to create the junit-platform.properties file in the src/test/resources folder. Using a property file for reporting is quite helpful if you want to define several different properties.

cucumber.publish.enabled=true

Step 9 – Create a Helper class in src/main/java

We have used Page Object Model with Cucumber and TestNG. Create a Helper class where we are initializing the web driver, initializing the web driver wait, defining the timeouts, and creating a private constructor of the class, it will declare the web driver, so whenever we create an object of this class, a new web browser is invoked. 

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.chrome.ChromeOptions;

public class HelperClass {

	 private static HelperClass helperClass;
     
	    private static WebDriver driver;
	    public final static int TIMEOUT = 5;
	      
	     private HelperClass() {
	           
	        WebDriverManager.chromedriver().setup();
			ChromeOptions options = new ChromeOptions();
			options.addArguments("--start-maximized");
	        driver = new ChromeDriver(options);
	        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
	     }      
	              
	    public static void openPage(String url) {
	        driver.get(url);
	    }
	  	      
	    public static WebDriver getDriver() {
	        return driver;              
	    }
	      
	    public static void setUpDriver() {
	          
	        if (helperClass==null) {
	              
	            helperClass = new HelperClass();
	        }
	    }
	      
	    public static void tearDown() {
	           
	        if(driver!=null) {
	             driver.close();
	             driver.quit();
	        }
	           
	       helperClass = null;
	   } 
	      
	}

Step 10 – Create Locator classes in src/main/java

Create a locator class for each page that contains the detail of the locators of all the web elements. Here, I’m creating 3 locator classes – LoginPageLocators, HomePageLocators, and ForgotPasswordLocators.

LoginPageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

	@FindBy(name = "username")
    public WebElement userName;
 
    @FindBy(name = "password")
    public WebElement password;
 
    @FindBy(id = "logInPanelHeading")
    public WebElement titleText;
 
    @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;
    
    @FindBy(xpath = "//*[@href='https://www.linkedin.com/company/orangehrm/mycompany/']")
    public  WebElement linkedInIcon;
    
    @FindBy(xpath = "//*[@href='https://www.facebook.com/OrangeHRM/']")
    public  WebElement faceBookIcon;
    
    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[4]/p")
    public  WebElement ForgotYourPasswordLink;
    
}

HomePageLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

	@FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
	public  WebElement homePageUserName;
 
}

ForgotPasswordLocators

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class ForgotPasswordLocators {
	
	@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/div/form/h6")
    public WebElement ForgotPasswordHeading;

}

Step 11 – Create Action classes in src/main/java

Create the action classes for each web page. These action classes contain all the methods needed by the step definitions. In this case, I have created 2 action classes – LoginPageActions, HomePageActions, and ForgotPasswordActions.

LoginPageActions

In this class, the very first thing will do is to create the object of the LoginPageLocators class so that we should be able to access all the PageFactory elements. Secondly, create a public constructor of LoginPageActions class.

import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;

public class LoginPageActions {

	LoginPageLocators loginPageLocators = null; 
	
    public LoginPageActions() {

    	this.loginPageLocators = new LoginPageLocators();

		PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
	}
 
	// Set user name in textbox
    public void setUserName(String strUserName) {
    	loginPageLocators.userName.sendKeys(strUserName);
    }
 
    // Set password in password textbox
    public void setPassword(String strPassword) {
    	loginPageLocators.password.sendKeys(strPassword);
    }
 
    // Click on login button
    public void clickLogin() {
    	loginPageLocators.login.click();
    }
 
    // Get the title of Login Page
    public String getLoginTitle() {
        return loginPageLocators.titleText.getText();
    }
       
    // Get the title of Login Page
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }
    
    // LinkedIn Icon is displayed
    public Boolean getLinkedInIcon() {
   
        return loginPageLocators.linkedInIcon.isDisplayed();
    }
    
    // FaceBook Icon is displayed
    public Boolean getFaceBookIcon() {
   
        return loginPageLocators.faceBookIcon.isDisplayed();
    }
    
    // Click on Forget Your Password link
    public void clickOnForgetYourPasswordLink() {
    	
    	loginPageLocators.ForgotYourPasswordLink.click();
    }
 
    public void login(String strUserName, String strPassword) {
 
        // Fill user name
        this.setUserName(strUserName);
 
        // Fill password
        this.setPassword(strPassword);
 
        // Click Login button
        this.clickLogin();
 
    }
}

HomePageActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;

public class HomePageActions {

	HomePageLocators homePageLocators = null;
   
	public HomePageActions() {
    	
		this.homePageLocators = new HomePageLocators();

		PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }

    // Get the User name from Home Page
    public String getHomePageText() {
        return homePageLocators.homePageUserName.getText();
    }

}

ForgotPasswordActions

import org.openqa.selenium.support.PageFactory;
import com.example.locators.ForgotPasswordLocators;
import com.example.utils.HelperClass;

public class ForgotPasswordActions {
	
	ForgotPasswordLocators forgotPasswordLocators = null;
	   
	public ForgotPasswordActions() {
    	
		this.forgotPasswordLocators = new ForgotPasswordLocators();

		PageFactory.initElements(HelperClass.getDriver(),forgotPasswordLocators);
    }

 
    // Get the Heading of Forgot Password page
    public String getForgotPasswordPageText() {
        return forgotPasswordLocators.ForgotPasswordHeading.getText();
    }
}

Step 12 – Create a Step Definition file in src/test/java

Create the corresponding Step Definition file of the feature file.

LoginPageDefinitions

import org.junit.jupiter.api.Assertions;
import com.example.actions.ForgotPasswordActions;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

public class LoginPageDefinitions{	

	LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();
    ForgotPasswordActions objForgotPasswordPage = new ForgotPasswordActions();
 
    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {
    	
    	HelperClass.openPage(url);
 
    }
 
    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {
 
        // login to application
        objLogin.login(userName, passWord);
 
        // go the next page
        
    }
    
    @When("User clicks on Forgot your Password Link")
    public void goToForgotYourPasswordPage() {
    	
    	objLogin.clickOnForgetYourPasswordLink();
    	
    }
 
    @Then("User should be able to login sucessfully and new page open")
    public void verifyLogin() {
 
        // Verify home page
        Assertions.assertTrue(objHomePage.getHomePageText().contains("Employee Information"));
 
    }
    
    @Then("User should be able to see error message {string}")
    public void verifyErrorMessage(String expectedErrorMessage) {
 
        // Verify home page
    	Assertions.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);
 
    }
    
    @Then("User should be able to see LinkedIn Icon")
    public void verifyLinkedInIcon( ) {
    	
    	Assertions.assertTrue(objLogin.getLinkedInIcon());
    }
    
    @Then("User should be able to see FaceBook Icon")
    public void verifyFaceBookIcon( ) {
    	
    	Assertions.assertTrue(objLogin.getFaceBookIcon());
    }
    
    @Then("User should navigate to a new page")
    public void verfiyForgetYourPasswordPage() {
    	
   	Assertions.assertEquals(objForgotPasswordPage.getForgotPasswordPageText(), "Reset Password");
    }
      
}

Step 13 – Create Hook class in src/test/java

Create the hook class that contains the Before and After hook to initialize the web browser and close the web browser.

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;

public class Hooks {
		
	@Before
    public static void setUp() {

       HelperClass.setUpDriver();
    }

	@After
	public static void tearDown(Scenario scenario) {

		//validate if scenario has failed
		if(scenario.isFailed()) {
			final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
			scenario.attach(screenshot, "image/png", scenario.getName()); 
		}	
		
		HelperClass.tearDown();
	}
}

Step 14 – Create a Cucumber Test Runner class in src/test/java

Cucumber needs a TestRunner class to run the feature files. It is suggested to create a folder with the name of the runner in the src/test/java directory and create the Cucumber TestRunner class in this folder. Below is the code of the Cucumber TestRunner class.

import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com.example")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example")
 
public class CucumberRunnerTests  {
 
}

Step 15 – Run the tests from Maven or Command Line

Use the below command to run the tests.

mvn clean verify 

Step 16 – Cucumber Report Generation

Below is the image of the Cucumber Report generated using the Cucumber Service.

The complete code can be found on GitHub.

Congratulations!! We have built the framework using Cucumber 7 with JUnit5.

How to tag and filter JUnit5 tests – @Tag

HOME

This tutorial explains how to run the specific tests in JUnit5 using @Tag annotation. Imagine, there are 500 test cases for different functionalities. Out of 500 test cases, 350 tests are related to the Integration test and the rest 150 are for the E2E test. We want to run only Integration tests. How this can be achieved? To overcome this problem, JUnit5 provides a filtering mechanism – @Tag annotation. We can apply the @Tag annotation on a test class test method, or both.

The JUnit Platform enforces the following rules for Tag:

  • A tag must not be null or blank.
  • A trimmed tag must not contain whitespace.
  • A trimmed tag must not contain ISO control characters.
  • A trimmed tag must not contain any of the following reserved characters.
    • ,: comma
    • (: left parenthesis
    • ): right parenthesis
    • &: ampersand
    • |: vertical bar
    • !: exclamation point

1. Annotating JUnit Test Class with Tag

Scenario 1 – Apply @Tag on the test class. It will run all the tests present within this test class.

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

@Tag("Sprint-5")
class JUnit5TagsTests {

    @Test
    void test_Addition() {
        System.out.println("test_Add()");
        assertEquals(18, 3 + 7 + 8);
    }

    @Test
    void test_Subtraction() {
        System.out.println("test_Subtraction()");
        assertEquals(18, 26 - 8);
    }

    @Test
    void test_Calculator() {
        System.out.println("test_Calculator()");
        assertEquals(18, 10 + 8);
        assertEquals(2, 10 - 8);
    }

    @Test
    void test_Functions() {
        System.out.println("test_Functions()");
        assertEquals(8, Math.sqrt(64));
        assertEquals(64, Math.pow(8,2));
    }

    @Test
    void test_IsEven() {
        System.out.println("test_IsEven()");
        assertEquals(0, 16%2);
    }

}

Let us say we have a number of classes, and we want to execute only this specific test class that is tagged as – @Sprint-5.

Go to the command line or in the case of IntelliJ to the terminal.

mvn clean test -Dgroups="Sprint-5"
mvn clean test -D"groups=Sprint-5"

The result of the above program is

2. Annotating JUnit Test Methods with Tag

With JUnit 5 we can filter tests by tagging a subset of them under a unique tag name.

Scenario 2 – Let’s say we have 5 tests, and we want to run 3 tests in the development environment, 1 test in both development and QA, 1 test in Production, and 1 test In-Progress. So we will tag the tests as below:

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

class JUnit5TagsTests {

    @Test
    @Tag("Development")
    void test1() {
        System.out.println("This test is for Development");
    }

    @Test
    @Tag("Development")
    void test2() {
        System.out.println("This test is for Development");
    }

    @Test
    @Tag("Development")
    @Tag("QA")
    void test3() {
        System.out.println("This test is for Development & QA");
    }

    @Test
    @Tag("Production")
    void test4() {
        System.out.println("This test is for Production");
    }

    @Test
    @Tag("Regression")
    @Tag("QA")
    void test5() {
        System.out.println("This is Regression Test for QA");
    }
}

To run the tests tagged with “production” in IntelliJ. Edit the configuration. Click on the Run and select “Edit Configurations”.

Select Tags from a list of components and mention the name of the tag you want to execute. Apply the changes by clicking on the “Apply” button and then click on the “OK” button.

Now, this creates a new Configuration as shown in the below image.

Click on this configuration. It will only run the test method tagged with @Production.

2. We can apply multiple tags on a single test case as well. Here, the test method – test_Calculator() is tagged with @Development and @QA.

    @Test
    @Tag("Development")
    @Tag("QA")
    void test_Calculator() {
        System.out.println("test_Calculator()");
        assertEquals(18, 10 + 8);
        assertEquals(2, 10 - 8);
    }

To run the above test, edit the configuration as shown below.

The output of the above program is

3. Filtering Tags with Maven Surefire Plugin

In Maven, we can run tests based on tags via the configuration parameters of the maven-surefire-plugin.

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <version>3.0.0-M5</version>
       <configuration>
           <!-- Include tags -->
           <groups>Development,QA,Production</groups>
           <!-- Exclude tags -->
           <excludedGroups>In-Progress</excludedGroups>
       </configuration>
</plugin>

If we now execute this plugin, it will execute all tests that are tagged as Development, QA, Production. 

If we want to exclude any specific test from the test execution, mention it with <excludeGroups>

The below-mentioned command will run all the tests except the test tagged with “In-Progress”.

mvn clean test -DexcludeGroups="In-Progress"

4. Creating your own custom tag annotation

If we are using the same tag @Tag(“Security”) or a combination with @Tag(“QA”) in several tests, instead of copying and pasting @Tag(“Security”), @Tag(“QA”) throughout your code base, you can create a custom composed annotation named @SecurityQATest as follows. @SecurityQATest can then be used instead, using 2 annotations every time.

The following example shows you how to create custom tag annotation for @Tag(“Security”), @Tag(“QA”).

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestTemplate;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD})
@Tag("Security")
@Tag("QA")
@Test
public @interface SecurityQATest {

}

    @SecurityQATest
    void test6() {
        System.out.println("This is Security Testing for QA");
    }

To run this test, use the below command:

mvn clean test -Dgroups="Security&QA"

The result of the above program is

Congratulations. We have understood the usage of @Tag annotation. Happy Learning!!

How to Parameterize tests in JUnit4

HOME

JUnit 4 has a feature called parameterized tests. Parameterized test means to execute the test multiple times with different sets of test data. This eliminates the redundancy of the code. This helps the developers to save time by eliminating the need to copy the code multiple times. Parameterizing tests can increase code coverage and provide confidence that the code is working as expected. These are the steps that need to be followed to create a parameterized test.

  • Annotate test class with @RunWith(Parameterized.class).
  • Create an instance variable for each “column” of test data.
  • It has a single constructor that contains the test data.
  • Create a public static method annotated with @Parameters that returns a Collection of Objects (as Array) as test data set.
  • Create your test case(s) using the instance variables as the source of the test data.

In a Maven project, to parameterize the tests in JUnit4, we need to add a dependency to POM.xml.

 <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>5.8.2</version>
      <scope>test</scope>
</dependency>

The test case will be invoked once for each row of data.

There are multiple ways to parameterize a test. They are the following:

  1. Parameterized Test with Constructor
  2. Parameterized Test with Parameter Annotation
  3. Parameterized Test using CSV File

Let us see parameterized tests in action.

1. Parameterized Test with Constructor

Steps to create a Parameterized JUnit test

1. Create a parameterized test class

Annotate your test class using @runWith(Parameterized.class).

Declaring the variable ‘num1’, ‘num2’, ‘num3’ as private and type as int.

@RunWith(value = Parameterized.class)
public class ParameterizedTest {

    private int num1;
    private int num2;
    private int num3;

2. Create a constructor

    public ParameterizedTest(int num1, int num2, int num3) {
        this.num1 = num1;
        this.num2 = num2;
        this.num3 = num3;
    }

3. Create a static method that generates and returns test data.

Creating a two-dimensional array (providing input parameters for multiplication). Using the asList method, we convert the data into a List type. Since the return type of method input is the collection.

Using @Parameters annotation to create a set of input data to run our test.

    @Parameterized.Parameters(name = "{index}: multiply({0}*{1}) = {2}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{
                {1, 1, 1},
                {2, 2, 4},
                {8, 2, 16},
                {4, 5, 20},
                {5, 5, 25}
        });
    }

The static method identified by @Parameters annotation returns a Collection, where each entry in the Collection will be the input data for one iteration of the test.

The complete code is shown below:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;

@RunWith(value = Parameterized.class)
public class ParameterizedTest {

    private int num1;
    private int num2;
    private int num3;

    public ParameterizedTest(int num1, int num2, int num3) {
        this.num1 = num1;
        this.num2 = num2;
        this.num3 = num3;
    }

    @Parameterized.Parameters(name = "{index}: multiply({0}*{1}) = {2}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{
                {1, 1, 1},
                {2, 2, 4},
                {8, 2, 16},
                {4, 5, 20},
                {5, 5, 25}
        });
    }

    @Test
    public void multiplication() {
        System.out.println("The product of "+num1+" and "+num2+" is "+num3);
        assertEquals((num1*num2), num3);
    }

}

The output of the above program is

2. Parameterized Test with Parameter Annotation

It is also possible to inject data values directly into fields without needing a constructor using the @Parameter annotation.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;

@RunWith(value = Parameterized.class)
public class ParameterizedTest1 {

    @Parameterized.Parameter(value = 0)
    public int num1;

    @Parameterized.Parameter(value = 1)
    public int num2;

    @Parameterized.Parameter(value = 2)
    public int num3;

    @Parameterized.Parameters(name = "{index}: multiply({0}*{1}) = {2}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{
                {1, 1, 1},
                {2, 2, 4},
                {8, 2, 16},
                {4, 5, 20},
                {5, 5, 24}
        });
    }

    @Test
    public void multiplication() {
        System.out.println("The product of "+num1+" and "+num2+" is "+num3);
        assertEquals((num1*num2), num3);
    }
}

The output of the above program is

3. Parameterized Test using CSV File

We can use an external CSV file to load the test data. This helps if the number of possible test cases is quite significant, or if test cases are frequently changed. The changes can be done without affecting the test code.

To start with, add a JUnitParams dependency to POM.xml

<dependency>
     <groupId>pl.pragmatists</groupId>
     <artifactId>JUnitParams</artifactId>
     <version>1.1.1</version>
     <scope>test</scope>
</dependency>

Let’s say that we have a CSV file with test parameters as JunitParamsTestParameters.csv:

Now let’s look at how this file can be used to load test parameters in the test method:

import junitparams.JUnitParamsRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.FileParameters;
import static org.junit.Assert.assertEquals;

@RunWith(JUnitParamsRunner.class)
public class ParameterizedTest2 {

    @Test
    @FileParameters("src/test/resources/JunitParamsTestParameters.csv")
    public void multiplication(int num1, int num2, int num3) {
        System.out.println("The product of "+num1+" and "+num2+" is "+num3);
        assertEquals((num1*num2), num3);
    }
}

The output of the above program is

The parameterized test enables us to execute the same test over and over again using different values.

Important annotations to be used during parameterization

  • @RunWith
  • @Parameters

Congratulations. We are done. I hope this tutorial is helpful to you. Happy Learning!!

JUnit4 Assertions
How to generate JUnit4 Report
Integration of Cucumber with Selenium and JUnit
Integration of Serenity with Cucumber6 and JUnit5
Integration of Serenity with JUnit4
Rest API Test in Cucumber BDD

How to configure Junit in Intellij

HOME

In this tutorial we will discuss to create a JUnit  project using IntelliJ. We will be at first creating a simple Java Project and will add JUnit5 as well as create a Maven Project, then we will add a basic Class and a JUnit Test for it.

Create a Java Project

Step 1 – Create a new Java Project.

To create a new Java project in Intellij, please refer to this tutorial.

Step 2 – Right click on the project and select Open Module Settings.

Step 3 – Go to the “Libraries” group, click the little plus (look up), and choose From Maven…option.

Step 4 – Search for “junit” — something like “junit:junit-4.13“. Click the OK button.

Step 5 – A new dialog will appear to confirm that “junit:junit:4.13.2” will be added to the module. Click the OK button.

Step 6 – This screens shows that junit:junit:4.13.2 is added to the Libraries. It contains the highlighted classes – junit-4.13.2.jar and hamcrest-core-1.3.jar. Click the “OK” button.

Step 7 – This image shows that the Junit is added to the External Libraries.

Step 8 – Create a Java Class – JUnit4Test under src and create a JUnit test to verify that it is installed properly.

import org.junit.Assert;
import org.junit.Test;

public class JUnit4Test {

    @Test
    public void Test() {

        String str1 = "Happy";
        String str2 = new String("Happy");
        Assert.assertEquals("String1 and String 2 are equal",str1, str2);

    }
}

Step 9 – There are many ways to run the test. One of the way is to Right-Click and select Run JUnit4Test

The successful execution of the test shows that the JUnit is configured properly.

Create a Maven Project

Add Junit dependency to the POM.xml and build the project.

<dependencies>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    
</dependencies>

Now we need to apply the changes in the build script. Press Ctrl+Shift+O or click Load Maven Changes in the notification that appears in the top-right corner of the editor.

Create a Java Class – JUnit4Test under src/test/java and create a JUnit test to verify that it is installed properly.

import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;

public class JUnitMavenTest {

    @Test
    public void Test() {

        String[] expected = {"happy","days","summer","spring"};
        String[] actual = {"happy","days","summer","spring"};

        assertArrayEquals("Expected and Actual Arrays are not equal",expected,actual);

    }
}

The output of the above program is

Similarly, to add JUnit5 we can add below mentioned dependencies to the POM.xml.

<dependency>
     <groupId>org.junit.jupiter</groupId>
     <artifactId>junit-jupiter-engine</artifactId>
     <version>5.8.2</version>
     <scope>test</scope>
</dependency>

<dependency>
     <groupId>org.junit.jupiter</groupId>
     <artifactId>junit-jupiter-api</artifactId>
     <version>5.8.2</version>
     <scope>test</scope>
</dependency>

Congratulations. We are able to add JUnit to Java or Maven project. Happy Learning!!

JUnit Tutorials

HOME

JUnit is an open source Unit Testing Framework for JAVA.
JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks.

JUnit4

Chapter 1 How to configure Junit in Intellij
Chapter 2 How to run JUnit5 tests through Command Line
Chapter 3 JUnit4 Assertions
Chapter 4 How to Parameterize tests in JUnit4
Chapter 5 How to generate JUnit4 Report
Chapter 6 Integration of Cucumber with Selenium and JUnit
Chapter 7 Integration of Serenity with Cucumber6 and JUnit5
Chapter 8 Integration of Serenity with JUnit4
Chapter 9 Rest API Test in Cucumber BDD
Chapter 10 Difference between JUnit4 and JUnit5
Chapter 11 Integration of REST Assured with JUnit4

JUnit5

Chapter 1 JUnit5 Assertions Example
Chapter 2 Grouped Assertions in JUnit 5 – assertAll()
Chapter 3 How to Retry Test in JUnit5 – @RepeatedTest
Chapter 4 How to disable tests in JUnit5 – @Disabled
Chapter 5 How to run JUnit5 tests in order
Chapter 6 How to tag and filter JUnit5 tests – @Tag
Chapter 7 Assumptions in JUnit5
Chapter 8 How to parameterized Tests in JUnit5
Chapter 9 How to run parameterized Selenium test using JUnit5
Chapter 10 Integration of Serenity with JUnit5
Chapter 11 Integration of Serenity with Cucumber6 and JUnit5
Chapter 12 How to generate JUnit5 Report – NEW

Gradle

Chapter 1 Gradle – Allure Report for Selenium and JUnit4
Chapter 2 Gradle Project with Cucumber, Selenium and JUnit4
Chapter 3 Gradle – Integration of Selenium and JUnit5

How to generate JUnit5 Report

HOME

For the successful execution of Agile testing requirements, a perfect test automation tool is required. And there are numerous factors to consider when creating a solid automation framework. One such component is reporting, which not only informs you of the success or failure of the project but also assists you in identifying potential bugs. JUnit is another useful framework that can add the ability to generate reports in Selenium. This tutorial explains the steps to generate the JUnit5 Report.

Prerequisite:

  1. Java 8 or higher installed
  2. Maven is installed
  3. Eclipse or IntelliJ are installed

Dependency List:

  1. Java 11
  2. JUnit Jupiter API – 5.10.0
  3. Maven – 3.8.1
  4. Maven Site Plugin – 3.12.0
  5. Maven Surefire Report Plugin – 3.1.2
  6. Maven Compiler Plugin – 3.10.1
  7. Json – 20230618
  8. Rest Assured – 5.3.2

Project Structure

To create a Maven project in Eclipse, please refer to this tutorial – Maven – How to import Maven project in Eclipse

To create a Maven project in Eclipse, please refer to this tutorial – How to create Maven project in IntelliJ

Implementation Steps

Step 1 – Add the Maven Site Plugin and Maven Surefire Report plugin

Maven Site Plugin

<plugin>
         <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-site-plugin</artifactId>
          <version>${maven.site.plugin.version}</version>
</plugin>

Maven Surefire Report Plugin

<reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-report-plugin</artifactId>
          <version>${maven.surefire.report.plugin.version}</version>
          <configuration>
            <outputName>JUnit5 Report</outputName>
          </configuration>
        </plugin>
      </plugins>
</reporting>

The complete POM.xml looks like

<project xmlns="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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>RestAssured_Junit5_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>RestAssured_Junit5_Demo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <rest-assurd.version>5.3.2</rest-assurd.version>
    <json.version>20220924</json.version>
    <hamcrest.version>1.3</hamcrest.version>
    <junit5.version>5.10.0</junit5.version>
    <maven.surefire.report.plugin.version>3.1.2</maven.surefire.report.plugin.version>
    <maven.compiler.plugin.version>3.10.1</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.0.0-M7</maven.surefire.plugin.version>
    <maven.compiler.source.version>11</maven.compiler.source.version>
    <maven.compiler.target.version>11</maven.compiler.target.version>
    <maven.site.plugin.version>3.12.0</maven.site.plugin.version>
  </properties>

  <dependencies>

    <!-- Rest Assured Dependency -->
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <version>${rest-assurd.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- JUNIT Jupiter API Dependency-->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit5.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- JUNIT Jupiter Engine Dependency-->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit5.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- JSON Dependency -->
    <dependency>
      <groupId>org.json</groupId>
      <artifactId>json</artifactId>
      <version>${json.version}</version>
    </dependency>

    <!-- Hamcrest Dependency -->
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-all</artifactId>
      <version>${hamcrest.version}</version>
      <scope>test</scope>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <version>${maven.site.plugin.version}</version>
      </plugin>
    </plugins>
  </build>

    <reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-report-plugin</artifactId>
          <version>${maven.surefire.report.plugin.version}</version>
          <configuration>
            <outputName>JUnit5 Report</outputName>
          </configuration>
        </plugin>
      </plugins>
    </reporting>

</project>

Step 2 – Create sample tests

The tests should be written in src/test/java directory. To know how to create a JSON Request body using JSONObject, please refer to this tutorial.

import io.restassured.http.ContentType;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

public class APITests {

        String BaseURL = "https://reqres.in/api";

    @Test
    public void createUser() {

        JSONObject data = new JSONObject();

        data.put("name", "NewUser1");
        data.put("job", "Testing");

        // GIVEN
        given()
                .contentType(ContentType.JSON)
                .body(data.toString())

                // WHEN
                .when()
                .post(BaseURL + "/users")

                // THEN
                .then()
                .statusCode(201)
                .body("name", equalTo("NewUser1"))
                .body("job", equalTo("Testing"))

    }

    @Test
    public void getUser() {

        // GIVEN
        given()
                .contentType(ContentType.JSON)

                // WHEN
                .when()
                .get(BaseURL + "/users/2")

                // THEN
                .then()
                .statusCode(200)
                .body("data.first_name", equalTo("Janet1"))

    }

}

Step 3 – Run the tests from the Command Line

Use the below command to run the tests from the command line

mvn clean test site

The output of the test execution is

Step 4 – JUnit5 Report generation

Maven Site Plugin creates a folder – site under the target directory.

To know about the test failure, go to the Failure Details Section.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!