Writing Tests for Web Applications With TestProject OpenSDK And JUnit 5

After you have integrated the TestProject OpenSDK with JUnit 5, you can start writing the actual test methods. This blog post describes how you can write tests for web applications with TestProject OpenSDK and JUnit 5.

After you have read this blog post, you:

  • Understand how you can write a new JUnit 5 test class that contains test methods which use the TestProject OpenSDK.
  • Can run automated tests which use the TestProject OpenSDK and JUnit 5.

Let's begin.

This blog post is the fourth part of my TestProject OpenSDK tutorial that's sponsored by TestProject.io. However, the views and opinions expressed in this tutorial are mine.

This blog post assumes that:

By the way, you might want to read the other parts of my TestProject OpenSDK tutorial.

Introduction to the System Under Test

During this blog post you will learn to write automated tests for the search function of this blog. The requirements of the search function are:

First, the search form is displayed on the sidebar and it's visible on every page which has a sidebar. That being said, when you write automated tests for the search function, you must open the front page of this blog (https://www.petrikainulainen.net/blog/) before you enter a search term to the search form.

The following figure identifies the location of the search form:

Second, when you want to use the search function, you have to enter the search term to the search form and press the enter key.

Third, if no results are found, the search result page displays the text: 'No results found.'. The following figure illustrates the layout of the search result page when no results are found:

Fourth, if search results are found, the search result page displays the found search results. The following figure illustrates the layout of the search result page when search results are found:

Next, you will learn to write automated tests for the search function.

Writing Tests for the Search Function

When you want to write automated tests for the search function, you must follow these steps:

First, you have to create a new test class and integrate the TestProject OpenSDK with JUnit 5. After you have done this, the source code of your test class looks as follows:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.chrome.ChromeOptions;

class BlogSearchTest {

    private static ChromeDriver driver;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}
This configuration ensures that all test methods which are added to the BlogSearchTest class are shown on the same test report. I like this approach because of these two reasons:

  • If a test case fails, I can identify the problematic feature by simply looking at the title of the test report.
  • I don't have to pay so such attention to customizing my test reports because the context of my test cases (one feature) is provided automatically.

If this doesn't make any sense to you now, you should read the next part of my TestProject OpenSDK tutorial which provides an introduction to the test reports generated by TestProject OpenSDK and describes how you can customize your test reports.

Second, you have to create the inner classes which contain the actual test methods. You can create these inner classes by following these steps:

  1. Create an inner class that contains the test method which ensures that the system under test is working as expected when no search results are found.
  2. Create an inner class that contains the test methods which ensure that the system under test is working as expected when one search result is found.

After you have created the required inner classes, the source code of your test class looks as follows:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.openqa.selenium.chrome.ChromeOptions;

class BlogSearchTest {

    private static ChromeDriver driver;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @Nested
    class WhenNoSearchResultsAreFound {

    }

    @Nested
    class WhenOneSearchResultIsFound {

    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}
You should separate different scenarios by using inner class because of these two reasons:

  • This approach makes your tests easy to read because the class hierarchy helps you to find the test methods which interest you.
  • It's likely that different scenarios requires different setup code. When you write nested tests with JUnit 5, you can add setup methods to the inner classes and add the required setup code to these setup methods. This means that your setup code is split into smaller chunks which are close to the test code that needs the setup code. In other words, this approach ensures that your setup code is easier to read and write.

Additional Reading:

Third, you have to write the test method which ensures that the system under test is working as expected when no search results are found. You can write this test method by following these steps:

  1. Open the front page of this blog (https://www.petrikainulainen.net/blog/).
  2. Enter the search term to the search form and press the enter key.
  3. Verify that the search result page displays the text: 'No results found.'.

After you have written this test method, the source code of your test class looks as follows:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class BlogSearchTest {

    private static ChromeDriver driver;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @Nested
    class WhenNoSearchResultsAreFound {

        @Test
        void shouldDisplayEmptySearchResultPage() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("noresults");
            searchField.sendKeys(Keys.ENTER);

            WebElement noResultElement = driver.findElement(
                    By.cssSelector(
                            ".template-search .content .post_box .archive_content"
                    )
            );
            assertThat(noResultElement.getText()).isEqualTo("No results found.");
        }
    }

    @Nested
    class WhenOneSearchResultIsFound {

    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Fourth, you have to write the test method which ensures that the search result page displays one search result when one search result is found. You can write this test method by following these steps:

  1. Open the front page of this blog (https://www.petrikainulainen.net/blog/).
  2. Enter the search term to the search form and press the enter key.
  3. Ensure that the search result page displays one search result.

After you have written this test method, the source code of your test class looks as follows:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class BlogSearchTest {

    private static ChromeDriver driver;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @Nested
    class WhenNoSearchResultsAreFound {

        @Test
        void shouldDisplayEmptySearchResultPage() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("noresults");
            searchField.sendKeys(Keys.ENTER);

            WebElement noResultElement = driver.findElement(
                    By.cssSelector(
                            ".template-search .content .post_box .archive_content"
                    )
            );
            assertThat(noResultElement.getText()).isEqualTo("No results found.");
        }
    }

    @Nested
    class WhenOneSearchResultIsFound {

        @Test
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            List<WebElement> searchResults = driver.findElements(
                    By.tagName("article")
            );
            assertThat(searchResults).hasSize(1);
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}

Fifth, you have to write the test method which ensures that the search result page displays the correct search result when one search result is found. You can write this test method by following these steps:

  1. Open the front page of this blog (https://www.petrikainulainen.net/blog/).
  2. Enter the search term to the search form and press the enter key.
  3. Ensure that the title of the displayed search result is correct.

After you have written this test method, the source code of your test class looks as follows:

import io.testproject.sdk.DriverBuilder;
import io.testproject.sdk.drivers.web.ChromeDriver;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class BlogSearchTest {

    private static ChromeDriver driver;

    @BeforeAll
    static void configureTestProjectOpenSDK() {
        driver = new DriverBuilder<ChromeDriver>(new ChromeOptions())
                .withCapabilities(new ChromeOptions())
                .build(ChromeDriver.class);
    }

    @Nested
    class WhenNoSearchResultsAreFound {

        @Test
        void shouldDisplayEmptySearchResultPage() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("noresults");
            searchField.sendKeys(Keys.ENTER);

            WebElement noResultElement = driver.findElement(
                    By.cssSelector(
                            ".template-search .content .post_box .archive_content"
                    )
            );
            assertThat(noResultElement.getText()).isEqualTo("No results found.");
        }
    }

    @Nested
    class WhenOneSearchResultIsFound {

        @Test
        void shouldDisplaySearchResultPageWithOneSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            List<WebElement> searchResults = driver.findElements(
                    By.tagName("article")
            );
            assertThat(searchResults).hasSize(1);
        }

        @Test
        void shouldDisplaySearchResultPageWithCorrectSearchResult() {
            driver.get("https://www.petrikainulainen.net/blog/");

            WebElement searchField = driver.findElement(By.id("s"));
            searchField.sendKeys("oneresult");
            searchField.sendKeys(Keys.ENTER);

            WebElement searchResult = driver.findElement(
                    By.tagName("article")
            );
            WebElement resultTitle = searchResult.findElement(
                    By.className("headline")
            );
            assertThat(resultTitle.getText())
                    .isEqualTo("Java Testing Weekly 22 / 2018");
        }
    }

    @AfterAll
    static void shutdownTestProjectOpenSDK() {
        driver.quit();
    }
}
If this would be a real-life software project, you should (obviously) write more comprehensive tests for the search function. In fact, if you interested in this topic, I think that you should get the example application from Github and write the missing tests yourself.

Let's move on and find out how you can run automated tests which use the TestProject OpenSDK and JUnit 5.

Running Your Automated Tests

You can run your tests by following these steps:

First, you have to start the TestProject agent and ensure that it's running before you run your tests. If you want to ensure that your agent is ready to run your tests, you have to follow these steps:

  1. Open the app.testproject.io website.
  2. Open the 'Agents' tab.
  3. Ensure that the status of your agent is: 'Ready'.

The following figure illustrates the layout of the 'Agents' page:

Second, you have to run your tests by using one of these options:

  • If you are using Gradle, you can run your tests by using the command: gradle clean test.
  • If you are using Maven, you can run your tests by using the command: mvn clean test.
  • You can also run (or debug) your tests by using your IDE.
When you run your tests, the TestProject agent sends test execution data to the TestProject plaform which generates test reports and publishes the generated reports on the TestProject reporting dashboard. If you want to get more information about the generated test reports, you should read the next part of my TestProject OpenSDK tutorial.

You can now write tests for web applications by using the TestProject OpenSDK and JUnit 5, and you know how you can run your tests. Let's summarize what you learned from this blog post.

Summary

This blog post has taught you four things:

  • You should consider using a configuration which ensures that all test methods found from the same test class are shown on the same test report.
  • You should separate different scenarios by using inner classes.
  • You must ensure that the TestProject agent is running before you run your tests.
  • When you run your tests, the TestProject agent sends test execution data to the TestProject plaform which generates test reports and publishes the generated reports on the TestProject reporting dashboard.

P.S. You can get the example application of this blog post from Github.

4 comments… add one
  • Jean Jul 3, 2021 @ 5:19

    Thank you so much for this tutorial. It is very informative. Is there a specific reason for not using the page Object Model.

    • Petri Jul 4, 2021 @ 23:04

      Hi,

      I am happy to hear that this blog post was useful to you. I didn't use page objects in this blog post because I wanted to keep things "as simple as possible". However, I have written another blog post that explains how you can share code with multiple tests by using page objects when you are writing your tests with TestProject OpenSDK and JUnit 5.

  • Sisir Nov 3, 2021 @ 17:03

    Hello, I want to upload the coded test to TestProject. But that the coded test is a partial code. How will I do it?
    Scenario:
    1. Open https://example.testproject.io/web/
    2. Fill up the first name.
    3. Fill up the password.
    I need the step #3 to be part of the Coded test. How will I do it?

    Regards
    Sisirkant

    • Petri Nov 3, 2021 @ 22:03

      Hi,

      You write the the required test by following these steps:

      1. Open the page by invoking the get() method of your driver object.
      2. Get the WebElement object which represents the name field by invoking the findElement() method of your driver object. You can use its id (name) as search criteria.
      3. Fill up the name by invoking the sendKeys() method of the WebElement class.
      4. Get the WebElement object which represents the password field by invoking the findElement() method of your driver object. You can use its id (password) as search criteria.
      5. Fill up the password by invoking the sendKeys() method of the WebElement class.
      6. Get the WebElement object which represents the login button by invoking the findElement() method of your driver object. You can use its id (login) as search criteria.
      7. Click the login button by invoking the click() method of the WebElement class.

      I hope that this helps. If you have any additional questions, don't hesitate to ask them.

Leave a Reply