Are you tired of writing tests which have a lot of boilerplate code? If so, get started with Spock Framework >>

JUnit 5 Tutorial: Writing Assertions With JUnit 5 Assertion API

This blog post describes how we can write assertions by using the JUnit 5 assertion API. After we have finished this blog post, we:

  • Can write basic assertions with JUnit 5.
  • Know how we can customize the error message shown when an assertion fails.
  • Understand how we can run multiple assertions as an assertion group.

Let’s begin.

Writing Assertions With JUnit 5

If we want to write assertions by using the “standard” JUnit 5 API, we must use the org.junit.jupiter.api.Assertions class. It provides static factory methods that we can use for writing assertions.

Before we will take a closer look at these methods, we have to know a few basic rules:

  • If we want to specify a custom error message that is shown when our assertion fails, we have to pass this message as the last method parameter of the invoked assertion method.
  • If we want to compare two values (or objects), we have to pass these values (or objects) to the invoked assertion method in this order: the expected value (or object) and the actual value (or object).

Next, we will find out how we can write assertions with the Assertions class. Let’s start by finding out how we can write assertions for boolean values.

Asserting Boolean Values

If we want to verify that a boolean value is true, we have to use the assertTrue() method of the Assertions class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is true")
    class WhenBooleanIsTrue {

        @Test
        @DisplayName("Should be true")
        void shouldBeTrue() {
            assertTrue(true);
        }
    }
}

If we want to verify that a boolean value is false, we have to use the assertFalse() method of the Assertions class. In order words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is false")
    class WhenBooleanIsFalse {

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false);
        }
    }
}

Next, we will find out how we can verify that an object is null or is not null.

Asserting That an Object Is Null or Is Not Null

If we want to verify that an object is null, we have to use the assertNull() method of the Assertions class. In other words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is null")
    class WhenObjectIsNull {

        @Test
        @DisplayName("Should be null")
        void shouldBeNull() {
            assertNull(null);
        }
    }
}

If we want to verify that an object is not null, we have to use the assertNotNull() method of the Assertions class. In other words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When object is not null")
    class WhenObjectIsNotNotNull {

        @Test
        @DisplayName("Should not be null")
        void shouldNotBeNull() {
            assertNotNull(new Object());
        }
    }
}

Let’s move on and find out how we can verify that two objects (or values) are equal or are not equal.

Asserting That Two Objects or Values Are Equal

If we want to verify that the expected value (or object) is equal to the actual value (or object), we have to use the assertEquals() method of the Assertions class. For example, if we want to compare two Integer objects, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects are equal")
    class WhenTwoObjectsAreEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 9;

            @Test
            @DisplayName("Should be equal")
            void shouldBeEqual() {
                assertEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

If we want to verify that the expected value (or object) is not equal to the actual value (or object), we have to use the assertNotEquals() method of the Assertions class. For example, if we want to compare two Integer objects, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects aren't equal")
    class WhenTwoObjectsAreNotEqual {

        @Nested
        @DisplayName("When objects are integers")
        class WhenObjectsAreIntegers {

            private final Integer ACTUAL = 9;
            private final Integer EXPECTED = 4;

            @Test
            @DisplayName("Should not be equal")
            void shouldNotBeEqual() {
                assertNotEquals(EXPECTED, ACTUAL);
            }
        }
    }
}

Next, we will find out how we can write assertions for object references.

Asserting Object References

If we want to ensure that two objects refer to the same object, we have to use the assertSame() method of the Assertions class. In other words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects refer to the same object")
    class WhenTwoObjectsReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = ACTUAL;

        @Test
        @DisplayName("Should refer to the same object")
        void shouldReferToSameObject() {
            assertSame(EXPECTED, ACTUAL);
        }
    }
}

If we want to ensure that two objects don’t refer to the same object, we have to use the assertNotSame() method of the Assertions class. In other words, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Writing assertions for objects")
class ObjectAssertionTest {

    @Nested
    @DisplayName("When two objects don't refer to the same object")
    class WhenTwoObjectsDoNotReferToSameObject {

        private final Object ACTUAL = new Object();
        private final Object EXPECTED = new Object();

        @Test
        @DisplayName("Should not refer to the same object")
        void shouldNotReferToSameObject() {
            assertNotSame(EXPECTED, ACTUAL);
        }
    }
}

Let’s move on and find out how we can verify that two arrays are equal.

Asserting That Two Arrays Are Equal

If we want to verify that two arrays are equal, we have to use the assertArrayEquals() method of the Assertions class. For example, if we want verify that two int arrays are equal, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for arrays")
class ArrayAssertionTest {

    @Nested
    @DisplayName("When arrays contain integers")
    class WhenArraysContainIntegers {

        final int[] ACTUAL = new int[]{2, 5, 7};
        final int[] EXPECTED = new int[]{2, 5, 7};

        @Test
        @DisplayName("Should contain the same integers")
        void shouldContainSameIntegers() {
            assertArrayEquals(EXPECTED, ACTUAL);
        }
    }
}
Two arrays are considered as equal if:

  • They are both null or empty.
  • Both arrays contain the “same” objects or values. To be more specific, JUnit 5 iterates both arrays one element at a time and ensures that the elements found from the given index are equal.

Next, we will find out how wen can verify that two iterables are equal.

Asserting That Two Iterables Are Equal

If we want to verify that two iterables are deeply equal, we have to use the assertIterableEquals() method of the Assertions class. For example, if we want verify that two Integer lists are deeply equal, we have to use this assertion:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

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

@DisplayName("Writing assertions for lists")
class ListAssertionTest {

    @Nested
    @DisplayName("When we compare two lists")
    class WhenWeCompareTwoLists {

        private final List<Integer> FIRST = Arrays.asList(1, 2, 3);
        private final List<Integer> SECOND = Arrays.asList(1, 2, 3);

        @Test
        @DisplayName("Should contain the same elements")
        void shouldContainSameElements() {
            assertIterableEquals(FIRST, SECOND);
        }
    }
}
Two iterables are considered as equal if:

  • They are both null or empty.
  • Both iterables contain the “same” objects or values. To be more specific, JUnit 5 iterates both iterables one element at a time and ensures that the elements found from the given index are equal.

Let’s move on and find out how we can write assertions for the exception thrown by the system under test.

Writing Assertions for Exceptions

If we want to write assertions for the exceptions thrown by the system under test, we have to use the assertThrows() method of the Assertions class. This method takes the following method parameters:

  • A Class object that specifies the type of the expected exception.
  • An Executable object that invokes the system under test.
  • An optional error message.

For example, if we want to verify that the system under test throws a NullPointerException, our assertion looks as follows:

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

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

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw the correct exception")
    void shouldThrowCorrectException() {
        assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException(); }
        );
    }
}

Because the assertThrows() method returns the thrown exception object, we can also write additional assertions for the thrown exception. For example, if we want to verify that the thrown exception has the correct message, we can use the following assertions:

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

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

@DisplayName("Writing assertions for exceptions")
class ExceptionAssertionTest {

    @Test
    @DisplayName("Should throw an exception that has the correct message")
    void shouldThrowAnExceptionWithCorrectMessage() {
        final NullPointerException thrown = assertThrows(
                NullPointerException.class,
                () -> { throw new NullPointerException("Hello World!"); }
        );
        assertEquals("Hello World!", thrown.getMessage());
    }
}

Next, we will find out how we can write assertions for the execution time of the system under test.

Writing Assertions for the Execution Time of the System Under Test

If we want to ensure that the execution of the system under test is completed before a specified timeout is exceeded, we can use the assertTimeout() and assertTimeoutPreemptively() methods of the Assertions class. Both of these methods take the following method parameters:

  • A Duration object that specifies the timeout.
  • An Executable or a ThrowingSupplier object that invokes the system under test.
  • An optional error message that is shown if the specified timeout is exceeded.

Even though these two methods are quite similar, they have one crucial difference. This difference is explained in the following:

  • If we use the assertTimeout() method, the provided Executable or ThrowingSupplier will be executed in the same thread as the code that calls it. Also, this method doesn’t abort the execution if the timeout is exceeded.
  • If we use the assertTimeoutPreemptively() method, the provided Executable or ThrowingSupplier will be executed in a different thread than the code that calls it. Also, this method aborts the execution if the timeout is exceeded.

As we see, we can verify that the execution of the system under test is completed before a specified timeout is exceeded by using one of these two options:

First, if we want that the execution is not aborted if the timeout is exceeded, we have to use the assertTimeout() method of the Assertions class. For example, if we want to verify that the system under test returns the message: ‘Hello world!’ before the specified timeout (50ms) is exceeded, we have to write assertions that look as follows:

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

import java.time.Duration;

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

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeout(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

Second, if we want that the execution is aborted if the timeout is exceeded, we have to use the assertTimeoutPreemptively() method of the Assertions class. For example, if we want to verify that the system under test returns the message: ‘Hello world!’ before the specified timeout (50ms) is exceeded, we have to write assertions that look as follows:

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

import java.time.Duration;

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

@DisplayName("Writing assertions for the execution time of the system under test")
class TimeoutAssertionTest {

    @Test
    @DisplayName("Should return the correct message before timeout is exceeded")
    void shouldReturnCorrectMessageBeforeTimeoutIsExceeded() {
        final String message = assertTimeoutPreemptively(Duration.ofMillis(50), () -> {
            Thread.sleep(20);
            return "Hello World!";
        });
        assertEquals("Hello World!", message);
    }
}

We can now write basic assertions with JUnit 5. Let’s move on and find out how we can customize the error messages which are shown by JUnit 5 if an assertion fails.

Providing a Custom Error Message

As we remember, if we want to specify a custom error message that is shown when our assertion fails, we have to pass this message as the last method parameter of the invoked assertion method. We can create this message by using one of these two options:

First, we can create a new String object and pass this object as the last method parameter of the invoked assertion assertion method. This is a good choice if our error message has no parameters. For example, if we want to provide a custom error message for an assertion which verifies that a boolean value is false, we have to write an assertion that looks as follows:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

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

@DisplayName("Write assertions for booleans")
class BooleanAssertionTest {

    @Nested
    @DisplayName("When boolean is false")
    class WhenBooleanIsFalse {

        @Test
        @DisplayName("Should be false")
        void shouldBeFalse() {
            assertFalse(false, "The boolean is not false");
        }
    }
}

Second, we can create a message supplier (Supplier<String>) and pass this supplier as the last method parameter of the invoked assertion method. If we use this approach, JUnit 5 creates the actual error messages only if our assertion fails. That’s why this is a good choice if we want to create a “complex” error message that has parameters.

For example, if we want to provide a custom error message for an assertion which verifies that a map contains the given key, we have to write an assertion that looks as follows:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

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

@DisplayName("Writing assertions for maps")
class MapAssertionTest {

    private static final String KEY = "key";
    private static final String VALUE = "value";

    private Map<String, String> map;

    @BeforeEach
    void createAndInitializeMap() {
        map = new HashMap<>();
        map.put(KEY, VALUE);
    }

    @Test
    @DisplayName("Should contain the correct key")
    void shouldContainCorrectKey() {
        assertTrue(
                map.containsKey(KEY), 
                () -> String.format("The map doesn't contain the key: %s", KEY)
        );
    }
}
It’s good to understand that the custom error message doesn’t override the default error message shown if an assertion fails. It is simply a prefix that is prepended to the default error message of the used assertion object. At first, this feels a bit weird, but it’s actually quite useful after you get used to it.

Next, we will find out how we can group assertions with JUnit 5.

Grouping Assertions

If we have to write an assertion for a state that requires multiple assertions, we can group our assertions by using the assertAll() method of the Assertions class. This method takes the following method parameters:

  • An optional heading that identifies the asserted state.
  • An array, a Collection, or a Stream of Executable objects which invoke our assertions.

When we invoke the assertAll() method, it invokes all assertions given as a method parameter and reports all assertion failures after all assertions have been run.

Let’s assume that we have to write an assertion which verifies that a Person object has the correct name. The source code of the Person class looks as follows:

public class Person {

    private String firstName;
    private String lastName;

    public Person() {}

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

As we can see, if we want to verify that a person has the correct name, we have to verify that the asserted Person object has the correct first and last name. In other words, we have to write an assertion that looks as follows:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

@DisplayName("Group multiple assertions")
class GroupAssertionsTest {

    private static final String FIRST_NAME = "Jane";
    private static final String LAST_NAME = "Doe";

    private Person person;

    @BeforeEach
    void createPerson() {
        person = new Person();
        person.setFirstName(FIRST_NAME);
        person.setLastName(LAST_NAME);
    }

    @Test
    @DisplayName("Should have the correct name")
    void shouldHaveCorrectName() {
        assertAll("name",
                () -> assertEquals(FIRST_NAME, 
                        person.getFirstName(), 
                        "The first name is incorrect"
                ),
                () -> assertEquals(LAST_NAME, 
                        person.getLastName(), 
                        "The last name is incorrect"
                )
        );
    }
}

We can now write basic assertions with JUnit 5, provide a custom error message that is shown when an assertion fail, and group assertions with JUnit 5.

Let’s summarize what we learned from this blog post.

Summary

This blog post has taught us four things:

  • If we want to write assertions by using the “standard” JUnit 5 API, we must use the org.junit.jupiter.api.Assertions class.
  • If we want to specify a custom error message that has no parameters, we have to create a new String object and pass this object as the last method parameter of the invoked assertion method.
  • If we want to specify a “complex” error message that has parameters, we have to create a message supplier (Supplier<String>) and pass this supplier as the last method parameter of the invoked assertion method.
  • If we have to write an assertion for a state that requires multiple assertions, we can group our assertions by using the assertAll() method of the Assertions class.

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

2 comments… add one
  • Hello,
    Thanks for this nice article. It really help me understand assertions.

    I have one query,
    In case of failed group assertion, is it possible to execute next statement



    assertAll(“test_Date Assertion”,
    () -> assertEquals(CommUtils.getXpathField(xmlSoapResponse, “responseCode”),”01″),
    () -> assertTrue(this.assertionUtility.isValidSOAPResponse(xmlSoapResponse)),
    () -> assertEquals(datesFromDB.getCurrentProcessingDate().toString(), processFromService));
    log.debug(“Second Set”);
    ……
    …..

    Thanks

    Reply

Leave a Comment