A complete guide to JUnit5 Assertions

Assertions are the statements that are used to assert conditions in tests.

In this article, we will go through different methods that are present in the Assertions( in JUnit5) class.

All the methods in Assertions class are static and for the readability purpose it is recommended to static import all methods of Assertions.class


1. Why Assertions?

Basically, assert statements are the ones that give final meaning to a test method. Whenever we write a test, assert statements make it either a success or fail.

Also assert statements describe what exactly we are expecting from this test setup, whether we want two objects to be equal or whether an object is null or not, or whether a condition is true or false.

All these methods have a lot of overloaded methods for different data types like int, double, String, char, boolean, Object etc. It also depends on the number of parameters required for an assertion type.

For example, a minimum of two parameters is required for assertEquals, while for assertTrue minimum number of parameters required is only one..

But the basic overload structure has mainly three variations, one with a minimum number of params required, the second with an additional failure reason message, and the third one with an additional failure message supplier.

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

Lets implement the different assert methods and explore how we can use them.

2. assertEquals and assertNotEquals

assertEquals is used to verify that two objects are equal.

assertNotEquals is used to verify that two objects are not equal.

One important point is that we should always implement equals and hashCode when we want to test the equality of two custom Objects, else it might not work as expected.

 @Test
  void testAssertEqualAndNotEquals() {
      var expected = "codingeek";
      var actual = "codingeek";

      assertEquals(expected, actual);

      assertNotEquals("Some random string", actual);
  }

3. assertArrayEquals

assertArrayEquals is used to check the equality of two arrays.

We have to make sure that the elements in both the arrays are in the same order.

 @Test
  void testAssertArrayEqual() {
      var expected = new char[]{'c','o','d','i','n','g','e','e','k'};
      var actual = "codingeek".toCharArray();

      assertArrayEquals(expected, actual);
  }

Note: If both the array objects are null then they are considered equal.

@Test
  void testAssertArrayEqual() {
      var expected = null;
      var actual = null;

      assertArrayEquals(expected, actual);
  }

4. assertNotNull and assertNull

We use assertNotNull when we want to test that an object is not null.

Similarly, assertNull is used to assert that an object is null.

  @Test
  void testAssertNullAndNotNull() {
      String nullObject = null;
      var nonNullObject = "codingeek";

      assertNull(nullObject);
      assertNotNull(nonNullObject);
  }

5. assertNotSame and assertSame

We use assertNotSame to test that variables do not refer to the same object.

Similarly, assertSame is used to assert that they refer to the same object.

  @Test
  void testAssertSameAndNotSame() {
    var expectedObject = new Object();
    var sameObject = expectedObject;

    assertSame(expectedObject, sameObject);

    var notSameObject = new Object();
    assertNotSame(sameObject, notSameObject);
  }

Note: With assertSame we test the reference of the objects and with assertEquals we check the values in the object and that is the main difference between the two and same for assertNotSame and assertNotEquals.


6. assertTrue and assertFalse

We use assertTrue to assert that the boolean variables is true.

Similarly, assertFalse is used to assert that the boolean variables is false.

 @Test
  void testAssertTrueAndFalse() {
        assertTrue(2 < 3);
        assertFalse(2 > 3);
  }

7. assertIterableEquals

assertIterableEquals verifies that two iterables are equal with a deep comparison i.e. they both should return the objects in the same order.

It is independent of the object type these iterables are generated from.

If both the iterables are null then also they are considered equals.

So let’s try implementing iterables generated from List and a Set which generates the elements in the same order.

  @Test
  void testAssertIterableEquals() {
    var listIterable = new ArrayList<>(Arrays.asList("a", "b", "c"));
    var setIterable = new LinkedHashSet<>(Arrays.asList("a", "b", "c"));

    assertIterableEquals(listIterable, setIterable);
    
    assertIterableEquals(null, null);
  }

8. assertLinesMatch

assertLinesMatch matches and assert the expected and the actual String list.

But this method has a slight difference than other assertion methods in the class. It does 3 level of validations to test the list of Strings.

For each pair of expected and actual lines it checks –

  • if expected.equals(actual) – if yes, then this is valid and moves to the next pair of lines
  • otherwise it treats the expected String as a regular expression and check via String.matches(String) – if yes, then this is valid and moves to the next pair of lines
  • otherwise check if expected line is a fast-forward marker, if yes apply fast-forward actual lines accordingly and goto 1.

A fast forward marker is an extended line that has >> at the beginning and end of the String. Examples –

  • >> We should not test this line >>
  • >> 5 >> – This is a special case as it says skip 5 lines.
@Test
void testAssertLinesMatch() {
    var expectedList = new ArrayList<>(Arrays.asList("a", "\\d+", "[a-z]*"));
    var actualList = new ArrayList<>(Arrays.asList("a", "100", "codingeek"));

    assertLinesMatch(expectedList, actualList);
    assertLinesMatch(expectedList.stream(), actualList.stream());
  }

9. assertAll

assertAll verifies that all the executables run without throwing any error.

In case of multiple executables, if any executables throws exception it will continue to run all the other executables, consolidates the exceptions and report all of them at once.

The heading passed will be included in error message.

@Test
void testAssertAll() {
    assertAll("Sitename",
            () -> assertTrue("Codingeek".startsWith("C")),
            () -> assertTrue("Codingeek".endsWith("k")),
            () -> assertEquals(9, "Codingeek".length())
    );
  }

In case of irrecoverable error like OutOfMemory error it will stop the execution.


10. assertTimeout

assertTimeout succeeds only if the supplied executable completes the execution within the given timeout duration.

This method executes in the same thread and hence waits for the executable to finish the operation. If we want to finish test without waiting for the executable to finish then we should use assertTimeoutPreemptively.

@Test
void testAssertTimeoutNotExceeded() {
  // Does not fail as the method returns in less than a second
  assertTimeout(Duration.ofSeconds(1), () -> "Codingeek.com");
}

@Test
void testAssertTimeoutFailure() {
  // Does fails as the method does not returns in less than a second
  // Total running time for this method is a bit more than 2000 milliseconds
  assertTimeout(Duration.ofSeconds(1), () -> Thread.sleep(2000));
}

11. assertTimeoutPreemptively

assertTimeoutPreemptively succeeds only if the supplied executable completes the execution within the given timeout duration.

The only difference from assertTimeout is that here the executable runs in a separate thread and hence it does not wait for the executable to complete the execution.

@Test
void timeoutExceededWithPreemptiveTermination() {
  // This test fails but it fails in around 10 milliseconds only 
  assertTimeoutPreemptively(Duration.ofMillis(10), () -> {
    Thread.sleep(5000);
  });

12. assertThrows and assertDoesNotThrow

assertThrows asserts that the supplied executable throws the exception of the expected type.

Similarly, assertDoesNotThrow asserts that the supplied executable does not throw any exception.

@Test
void testAssertThrows() {
  Throwable throwable =
      assertThrows(
          ArithmeticException.class,
          () -> {
            var number = 10 / 0;
          });
  assertEquals("/ by zero", throwable.getMessage());
}

@Test
void testAssertDoesNotThrow() {
  assertDoesNotThrow(() -> {});
}

13. fail

If we want to fail a test on some condition then we can use fail method. Calling this method results in AssertionFailedError.

@Test
void testFail() {
  var returnValue = (int) (Math.random() * 100);
  if (returnValue % 2 == 0) {
    fail("This value should be odd");
  }
}

14. Conclusion

In this article we have discussed all the different static methods that Assertions class provide in JUnit5.

Complete code samples are present on Github project.

An investment in knowledge always pays the best interest. I hope you like the tutorial. Do come back for more because learning paves way for a better understanding

Do not forget to share and Subscribe.

Happy coding!! 😊

Recommended -

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x