An Overview of JUnit 5 Assertions with Examples

This article will explore the JUnit 5 Assertions API, go in-depth with examples of building fundamental assertions, and look at customizing the error message that appears when an assertion fails. We’ll also discuss how to execute many assertions simultaneously as an assertion group in our last section. So, let’s begin!

What are JUnit Assertions?

As per the official documentation of JUnit 5, Assertion is defined as:

Assertions is a collection of utility methods that support asserting conditions in tests.

The concept of Assertions is super important while testing whether manual or automated. Assertions are used as a validation stage that decides if the test case was successful or not. If an application produces a result that matches the expected value, the assert statement is considered to be true.

JUnit 5 Assertion API

As we know, the JUnit framework is a popular test automation framework for unit testing in Java. The JUnit 5 also known as Jupiter, the most recent version of JUnit has many enhancements on assertions over the past version i.e. JUnit 4. JUnit Jupiter API comes with an org.junit.jupiter.api.Assertions class that bundles a wide range of static utility methods to be used in our test cases.

  • It contains overloaded assertion methods to support primitives, objects, collections, arrays, and streams.
  • With the support of JDK 8 and Lambda expressions, the expected value can be passed as a Supplier in assert statements.
  • We must build a new String object and provide it as the last method argument to the called assertion method to define a custom error message with no parameters.
  • It is necessary to define a message supplier (Supplier) and send it as the last method argument to the called assertion method to set a “complex” error message with parameters.
  • Whenever an assertion fails, it will throw an AssertionFailedError or one of its subclasses.

Visit Testing Java Code tutorials page, to learn more about JUnit 5.

Project Setup

Let’s assume you have a Maven, Spring Boot Project. Refer to this article for more details.

To begin with, add the following dependency to your Maven project:

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

Now, let’s explore a few vital JUnit assert methods using an example in the next section!

Classification of Assertion based on Data Types

Asserting Boolean values

We frequently get across situations where we have to utilize assertion on Boolean values to determine whether or not an action has been triggered. The following two methods are provided by the Jupiter API for asserting the Boolean data type:

1. assertTrue()

It verifies a condition specified as true. Following overloaded methods are available for assertTrue():

assertTrue(boolean condition)
assertTrue(boolean condition, Supplier<String> messageSupplier)
assertTrue(BooleanSupplier booleanSupplier)
assertTrue(BooleanSupplier booleanSupplier, String message)
assertTrue(boolean condition, String message)
assertTrue(BooleanSupplier booleanSupplier, Supplier<String> messageSupplier)

Let’s have a look at the following example:

   @Test
   public void testAssertTrue() {
       assertTrue(2 < 9);
   }

   @Test
   public void testAssertTrueWithBooleanSupplier() {
       BooleanSupplier booleanSupplier = () -> Math.abs(9) == 9;
       assertTrue(booleanSupplier);
   }


   @Test
   public void testAssertTrueWithCustomMessage() {
       assertTrue(10 == 0, "Assertion is unsuccessful");
   }

In the above example, the top two test cases are passed and one failed with the following Custom Error Message.

JUnit5 assertions with examples

2. assertFalse()

It verifies a condition specified as false. Following overloaded methods are available for assertFalse():

assertFalse(boolean condition)
assertFalse(boolean condition, String message)
assertFalse(boolean condition, Supplier<String> messageSupplier)
assertFalse(BooleanSupplier booleanSupplier)
assertFalse(BooleanSupplier booleanSupplier, String message)
assertFalse(BooleanSupplier booleanSupplier, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testAssertFalse() {
    assertFalse(11 < 9);
}

@Test
public void testAssertFalseWithBooleanSupplier() {
    BooleanSupplier booleanSupplier = () -> Math.incrementExact(9) == 9;
    assertFalse(booleanSupplier);
}


@Test
public void testAssertFalseWithCustomMessage() {
    assertFalse(10 == 10, "Assertion is unsuccessful");
}

One test case fails with the custom error message as shown below:

JUnit5 assertions with examples

Asserting on Objects

The programming of real-world applications requires us to take decisions depending on an object’s state, such as whether it is null or not, equal or not, the same or not the same, etc. To verify it via JUnit5, it provides us with several utility methods to use in our test cases:

To verify if null or not null

1. assertNull()

The assertNull() function verifies that the value of actual is null. Following overloaded methods are available for assertNull():

assertNull(Object actual)
assertNull(Object actual, String message)
assertNull(Object actual, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testNull() {
    Student student = mockStudentService.getStudentById(1);
    System.out.println("Student retrieved is: " + student);
    assertNull(student);
}

@Test
public void testNullWithCustomMessage() {
    Student student = mockStudentService.getStudentById(10);
    System.out.println("Student retrieved with roll number: " + student.getId());
    assertNull(student, "Assertion failed");
}

The output is shown below:

JUnit5 assertions with examples

 

JUnit5 assertions with examples

2. assertNotNull()

The assertNotNull() function states that the value of actual is not null. Following overloaded methods are available for assertNotNull():

assertNotNull(Object actual)
assertNotNull(Object actual, String message)
assertNotNull(Object actual, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testNotNull() {
    Student student = mockStudentService.getStudentById(10);
    System.out.println("Student retrieved with id: " + student.getId());
    assertNotNull(student);
}

@Test
public void testNotNullWithCustomMessage() {
    Student student = mockStudentService.getStudentById(1);
    System.out.println("Student is: " + student);
    assertNotNull(student, "Assertion failed");
}

The output window snapshot is shown below:

JUnit5 assertions with examples

JUnit5 assertions with examples

To verify equal or not equal

1. assertEquals()

The assertEquals() function verifies that the value of expected and actual parameters are equal. Following are a few of the overloaded methods that are available for assertEquals():

assertEquals(short expected, short actual)
assertEquals(short expected, short actual, String message)
assertEquals(short expected, short actual, Supplier<String> messageSupplier)

Please note that it supports several other combinations with the wrapper class Short as well. It exists for byte, int, long, float, double, char, and corresponding wrapper classes.

Let’s have a look at the following code snippet:

@Test
public void testAssertEquals() {
    int i = 1;
    assertEquals(2, ++i);
}

@Test
public void testAssertEqualsWithMessageSupplier() {
    int i = 1;
    int j = 2;
    Supplier<String> messageSupplier  = () -> "Math.addExact(i,j) test failed";
    assertEquals(5, Math.addExact(i, j), messageSupplier);
}

The output window snapshot is shown below:

JUnit5 assertions with examples

2. assertNotEquals()

The assertNotEquals() function verifies that the value of expected and actual parameters are not equal. Following overloaded methods are available for assertNotEquals():

assertNotEquals(short unexpected, short actual)
assertNotEquals(short unexpected, short actual, String message)
assertNotEquals(Short unexpected, short actual, Supplier<String> messageSupplier)

Please note that it supports several other combinations with the wrapper class Short as well. It exists for byte, int, long, float, double, char, and corresponding wrapper classes. The following example demonstrates the use of the method:

@Test
public void testAssertNotEquals() {
    int i = 1;
    assertNotEquals(2, i++);
}

@Test
public void testAssertNotEqualsWithMessageSupplier() {
    int i = 1;
    int j = 2;
    Supplier<String> messageSupplier = () -> "Math.addExact(i,j) test failed";
    assertNotEquals(3, Math.addExact(i, j), messageSupplier);
}

The output window snapshot is shown below:

 

JUnit5 assertions with examples

Asserting Object References

Programmatically, we often write code where an object is a part of the main object, in other words, the reference of both Object A and Object B points to the same memory destination. Let’s have a look at below assertion methods which helps us to test the flow:

1. assertSame()

The assertSame() function verifies that the value of expected and actually refers to the exact same object. Following overloaded methods are available for assertSame():

assertSame(Object expected, Object actual)
assertSame(Object expected, Object actual, String message)
assertSame(Object expected, Object actual, Supplier<String> messageSupplier)

The following example demonstrates the use of the method:

@Test
 public void testAssertSame() {
     Student A = new Student();
     Student B = A;
     assertSame(A,B);
 }

As per expectations, the above test case passes successfully.

2. assertNotSame()

The assertSame() function verifies that the value of expected and actual do not refer to the exact same object. Following overloaded methods are available for assertNotSame():

assertNotSame(Object unexpected, Object actual)
assertNotSame(Object unexpected, Object actual, String message)
assertNotSame(Object unexpected, Object actual, Supplier<String> messageSupplier)

The following example demonstrates the use of the method:

@Test
public void testAssertNotSame() {
    Student A = new Student();
    Student B = new Student();
    assertNotSame(A,B);
}

As per expectations, the above test case passes successfully.

Asserting on List and Streams

Lists and Streams are the most important data structure to store and group data. The following assertion method works on the List and Stream data type:

assertLinesMatch()

The assertLinesMatch verifies that the expected list of String matches the actual list. The following overloaded methods are available for assertLinesMatch():

assertLinesMatch(List<String> expectedLines, List<String> actualLines)
assertLinesMatch(List<String> expectedLines, List<String> actualLines, String message)
assertLinesMatch(List<String> expectedLines, List<String> actualLines, Supplier<String> messageSupplier)
assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines)
assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines, String message)
assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines, Supplier<String> messageSupplier)

As per the official documentation, this method differs from other assertions that effectively only check String.equals(Object), in that it uses the following staged matching algorithm:

For each pair of expected and actual lines do

  1. Check if expected.equals(actual) – if yes the expected line is equal to the actual one, continue with the next pair
  2. Treat expected as a regular expression and check via String.matches(String) – if yes, continue with the next pair
  3. Check if the expected line is a fast-forward marker, if yes apply to fast-forward actual lines accordingly and go to step 1.

The following test snippet uses the above utility method:

@Test
public void testAssertLinesMatch() {
    List<String> expected = Arrays.asList("JUnit", "\\d+", "Tutorial");
    List<String> actual = Arrays.asList("JUnit", "11", "Tutorial");
    assertLinesMatch(expected,actual);
}

@Test
public void testAssertLinesMatchFailsWithCustomMessage() {
    List<String> expected = Arrays.asList("JUnit", "12", "Tutorial");
    List<String> actual = Arrays.asList("JUnit", "11", "Tutorial");
    assertLinesMatch(expected,actual,"Assertion fails");
}

The output window snapshot is shown below:

Asserting on Arrays

Another widely used data structure is arrays, which allow us to store several values in a single variable rather than declaring separate variables for each item. During testing, we often encounter a scenario where we have to verify that two arrays are equal, let’s see the following assertion method to see how it works:

assertArrayEquals()

Following overloaded methods are available for assertArrayEquals():

assertArrayEquals(boolean[] expected, boolean[] actual) 
assertArrayEquals(boolean[] expected, boolean[] actual, String message)
assertArrayEquals(boolean[] expected, boolean[] actual, Supplier<String> messageSupplier)

The above methods are available for char[], byte[], short[], int[], long[], float[], double[] and Object[].

Let’s have a look at the following code snippet:

@Test
public void testArrayEquals() {
    int[] rollNumbersExpected = {1, 2, 3, 4, 5};
    int[] rollNumbersActual = mockStudentService.getStudentsRollNumbers();
    Arrays.stream(rollNumbersActual).forEach(rollNo -> System.out.println(rollNo));
    assertArrayEquals(rollNumbersExpected, rollNumbersActual);
}

The output window snapshot is shown below:

JUnit5 assertions with examples

Asserting Iterables

Iterables can be defined as an object that can be iterated over or looped over using a for a loop. They are a class of objects that include lists, tuples, sets, dictionaries, strings, and more. In a practical application, iterables are commonly used thus there exist several assertion utilities for testing.

assertIterableEquals()

This method verifies two iterables to check if they are equal or not. When two iterables are encountered (including expected and real), assertArrayEquals(Object[], Object[]) checks for deep equality; if this happens, both iterators’ return equal elements in the same order. It is not required that the iterables are of the same kind. If both iterables are null, the statement results as equal. Following overloaded methods are available for assertIterableEquals():

assertIterableEquals(Iterable<?> expected, Iterable<?> actual)
assertIterableEquals(Iterable<?> expected, Iterable<?> actual, String message)
assertIterableEquals(Iterable<?> expected, Iterable<?> actual, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
 public void testAssertIterable() {
     Iterable<String> expected = new ArrayList<>(Arrays.asList("Junit", "Tutorials"));
     Iterable<String> actual = new LinkedList<>(Arrays.asList("Junit", "Tutorials"));
     assertIterableEquals(expected, actual);
 }

As per expectation, the test passes successfully.

Assertions for Exceptions

An exception is the most important programming aspect where we handle uncertain events. To verify such cases are handled by the following assertion methods:

1. assertThrows()

This assertion method verifies that running the specified executable will throw an exception of the expected type and return the exception. Following overloaded methods are available for assertThrows():

<T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable)
<T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, String message)
<T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testAssertThrows() {
    Throwable exception = assertThrows(
            IllegalArgumentException.class,
            () -> {
                throw new IllegalArgumentException("Illegal Argument Expression occurred");
            }
    );
    assertEquals("Illegal Argument Expression occurred", exception.getMessage());
}

As per expectation, the test case passes successfully.

2. assertDoesNotThrow()

Following overloaded methods are available for assertDoesNotThrow():

void assertDoesNotThrow(Executable executable)
void assertDoesNotThrow(Executable executable, String message)
void assertDoesNotThrow(Executable executable, Supplier<String> messageSupplier)
<T> T assertDoesNotThrow(ThrowingSupplier<T> supplier)
<T> T assertDoesNotThrow(ThrowingSupplier<T> supplier, String message)
<T> T assertDoesNotThrow(ThrowingSupplier<T> supplier, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testAssertDoesNotThrow() {
    String message = assertDoesNotThrow(() -> { return "Happy Learning"; } );
    assertEquals("Happy Learning", message);
}

As per expectation, the test case passes successfully with the correct message returned.

Assertions for the System Under Test’s Execution Time

1. assertTimeout()

Asserts that execution of the supplied executable completes before the given timeout is exceeded. The calling code’s current thread will be used to execute the given executable. Therefore, even if the timeout is exceeded, the supplier’s execution won’t be terminated immediately. Following overloaded methods are available for assertTimeout():

void assertTimeout(Duration timeout, Executable executable)
void assertTimeout(Duration timeout, Executable executable, String message)
void assertTimeout(Duration timeout, Executable executable, Supplier<String> messageSupplier)
<T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier)
<T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier, String message)
<T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier, Supplier<String> messageSupplier)

It takes the following parameters:

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

Let’s have a look at the following code snippet:

@Test
 public void testAssertTimeout() {
     assertTimeout(
             ofSeconds(2),
             () -> {
                 // code that requires less then 2 minutes to execute
                 Thread.sleep(1000);
             }
     );
 }

2. assertTimeoutPreemptively()

Asserts that execution of the supplied executable completes before the given timeout is exceeded. The thread in which the executable runs will be distinct from the thread in which the calling code runs. In addition, if the timeout is exceeded, the execution of the executable will be preemptively terminated. Following overloaded methods are available for assertTimeoutPreemptively():

void assertTimeoutPreemptively(Duration timeout, Executable executable)
void assertTimeoutPreemptively(Duration timeout, Executable executable, String message)
void assertTimeoutPreemptively(Duration timeout, Executable executable, Supplier<String> messageSupplier)
<T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier)
<T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier, String message)
<T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier, Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testAssertTimeoutPreemptivelyFails() {
    assertTimeoutPreemptively(ofMillis(10), () -> {
        // Simulate task that takes more than 10 ms.
        Thread.sleep(100);
    });
}

The output window snapshot is shown below:

If you are interested to check other examples of how to test for Exception, have a look at the “Test for Exception in JUnit 5 and JUnit 4” tutorial.

Fail Method – fail()

The fail assertion fails a test throwing an AssertionFailedError. This is useful when the development is still ongoing. Following overloaded versions are available:

<V> V fail()
<V> V fail(String message)
<V> V fail(String message, Throwable cause)
<V> V fail(Throwable cause)
<V> V fail(Supplier<String> messageSupplier)

Let’s have a look at the following code snippet:

@Test
public void testFailMethod() {
    fail("Service is under development");
}

The output window snapshot is shown below:

Grouped Assertions

Grouped assertions are useful when you need to run many assertions simultaneously and receive a single, aggregated report as a result. This is possible by using assertAll () assertion.

assertAll()

This assertion enables the development of group assertions, where each assertion is run and its failures are reported together. This assertion accepts a Stream of Executable and a header that will be used in the message string for the MultipleFailureError. Following overloaded versions are supported:

void assertAll(Executable... executables) throws MultipleFailuresError 
void assertAll(String heading, Executable... executables) throws MultipleFailuresError
void assertAll(Collection<Executable> executables) throws MultipleFailuresError
void assertAll(String heading, Collection<Executable> executables) throws MultipleFailuresError 
void assertAll(Stream<Executable> executables) throws MultipleFailuresError 
void assertAll(String heading, Stream<Executable> executables) throws MultipleFailuresError

Let’s have a look at the following code snippet:

@Test
public void testAssertAll() {
    int i = 2;
    Student student = null;
    assertAll(
            "heading",
            () -> assertEquals(4, i + i, "i+i"),
            () -> assertEquals("junit", "JUNIT".toLowerCase()),
            () -> assertNull(student, "Student object is null")
    );
}

As per expectation, the test case passes successfully.

Conclusion

In this article, we have gone through the basics of JUnit5 Assertion API and saw many examples of different assertion methods being supported by the library. We have seen that JUnit Jupiter offers a large number of assertions to assist us in writing test code that is fluent and clean.

Through these assertions, it would be easier for us to test code at a very early stage i.e. during the development phase.  If you’re a techie who wants to improve the quality of his or her code, the Testing Java Code page is a great place to start. If you find this article helpful, don’t forget to share your feedback or thoughts in the comments section.

Video lessons

If you like video tutorials,  then have a look at the following video course: “Testing Java with JUnit and Mockito“. This video course is for absolute beginners and you do not need to have any prior knowledge of testing Java applications to enrol.

Happy learning!