Behauptungen in JUnit 4 und JUnit 5

1. Einleitung

In diesem Artikel werden wir die in JUnit verfügbaren Aussagen im Detail untersuchen.

Nach der Migration von JUnit 4 zu JUnit 5 und einem Leitfaden zu JUnit 5 gehen wir nun auf die verschiedenen in JUnit 4 und JUnit 5 verfügbaren Zusicherungen ein.

Wir werden auch die Verbesserungen hervorheben, die an den Behauptungen mit JUnit 5 vorgenommen wurden.

2. Behauptungen

Assertions sind nützliche Methoden zur Unterstützung der Assertionsbedingungen in Tests . Auf diese Methoden kann über die Assert- Klasse in JUnit 4 und die Assertions- Klasse in JUnit 5 zugegriffen werden .

Um die Lesbarkeit des Tests und der Aussagen selbst zu verbessern, wird immer empfohlen, die jeweilige Klasse statisch zu importieren . Auf diese Weise können wir direkt auf die Assertionsmethode selbst verweisen, ohne die darstellende Klasse als Präfix.

Lassen Sie uns die mit JUnit 4 verfügbaren Behauptungen untersuchen.

3. Aussagen in JUnit 4

In dieser Version der Bibliothek sind Zusicherungen für alle primitiven Typen, Objekte und Arrays (entweder von primitiven oder von Objekten) verfügbar .

Die Parameterreihenfolge innerhalb der Zusicherung ist der erwartete Wert, gefolgt vom tatsächlichen Wert. Optional kann der erste Parameter eine String- Nachricht sein, die die Nachrichtenausgabe der ausgewerteten Bedingung darstellt.

Es gibt nur einen geringfügig anderen Unterschied in der Definition der assertThat- Assertions, aber wir werden sie später behandeln.

Beginnen wir mit der assertEquals .

3.1. assertEquals

Die assertEquals- Zusicherung überprüft, ob der erwartete und der tatsächliche Wert gleich sind:

@Test public void whenAssertingEquality_thenEqual() { String expected = "Baeldung"; String actual = "Baeldung"; assertEquals(expected, actual); }

Es ist auch möglich, eine Nachricht anzugeben, die angezeigt werden soll, wenn die Zusicherung fehlschlägt:

assertEquals("failure - strings are not equal", expected, actual);

3.2. assertArrayEquals

Wenn wir behaupten möchten, dass zwei Arrays gleich sind, können wir assertArrayEquals verwenden:

@Test public void whenAssertingArraysEquality_thenEqual() { char[] expected = {'J','u','n','i','t'}; char[] actual = "Junit".toCharArray(); assertArrayEquals(expected, actual); }

Wenn beide Arrays null sind , werden sie von der Assertion als gleich betrachtet:

@Test public void givenNullArrays_whenAssertingArraysEquality_thenEqual() { int[] expected = null; int[] actual = null; assertArrayEquals(expected, actual); }

3.3. assertNotNull und assertNull

Wenn wir testen möchten, ob ein Objekt null ist , können wir die assertNull- Assertion verwenden:

@Test public void whenAssertingNull_thenTrue() { Object car = null; assertNull("The car should be null", car); }

Umgekehrt können wir die assertNotNull-Assertion verwenden , wenn wir behaupten möchten, dass ein Objekt nicht null sein soll.

3.4. assertNotSame und assertSame

Mit assertNotSame kann überprüft werden, ob zwei Variablen nicht auf dasselbe Objekt verweisen:

@Test public void whenAssertingNotSameObject_thenDifferent() { Object cat = new Object(); Object dog = new Object(); assertNotSame(cat, dog); }

Andernfalls können wir die assertSame- Assertion verwenden , wenn wir überprüfen möchten, ob zwei Variablen auf dasselbe Objekt verweisen .

3.5. assertTrue und assertFalse

Wenn wir überprüfen möchten, ob eine bestimmte Bedingung wahr oder falsch ist , können wir jeweils die assertTrue- Assertion oder die assertFalse-Assertion verwenden :

@Test public void whenAssertingConditions_thenVerified() { assertTrue("5 is greater then 4", 5 > 4); assertFalse("5 is not greater then 6", 5 > 6); }

3.6. Scheitern

Die Fail- Assertion schlägt einen Test fehl, der einen AssertionFailedError auslöst . Es kann verwendet werden, um zu überprüfen, ob eine tatsächliche Ausnahme ausgelöst wird oder wenn ein Test während seiner Entwicklung fehlschlagen soll.

Mal sehen, wie wir es im ersten Szenario verwenden können:

@Test public void whenCheckingExceptionMessage_thenEqual() { try { methodThatShouldThrowException(); fail("Exception not thrown"); } catch (UnsupportedOperationException e) { assertEquals("Operation Not Supported", e.getMessage()); } }

3.7. behaupten, dass

Die assertThat- Assertion ist die einzige in JUnit 4, die eine umgekehrte Reihenfolge der Parameter im Vergleich zu den anderen Assertions aufweist.

In diesem Fall enthält die Zusicherung eine optionale Fehlermeldung, den tatsächlichen Wert und ein Matcher- Objekt.

Mal sehen, wie wir mit dieser Behauptung prüfen können, ob ein Array bestimmte Werte enthält:

@Test public void testAssertThatHasItems() { assertThat( Arrays.asList("Java", "Kotlin", "Scala"), hasItems("Java", "Kotlin")); } 

Weitere Informationen zur leistungsstarken Verwendung des AssertThat Assertion with Matcher- Objekts finden Sie unter Testen mit Hamcrest.

4. JUnit 5 Behauptungen

JUnit 5 behielt viele der Assertionsmethoden von JUnit 4 bei und fügte einige neue hinzu, die die Java 8-Unterstützung nutzen.

Auch in dieser Version der Bibliothek sind Zusicherungen für alle primitiven Typen, Objekte und Arrays (entweder Primitive oder Objekte) verfügbar .

The order of the parameters of the assertions changed, moving the output message parameter as the last parameter. Thanks to the support of Java 8, the output message can be a Supplier, allowing lazy evaluation of it.

Let's start reviewing the assertions available also in JUnit 4.

4.1. assertArrayEquals

The assertArrayEquals assertion verifies that the expected and the actual arrays are equals:

@Test public void whenAssertingArraysEquality_thenEqual() { char[] expected = { 'J', 'u', 'p', 'i', 't', 'e', 'r' }; char[] actual = "Jupiter".toCharArray(); assertArrayEquals(expected, actual, "Arrays should be equal"); }

If the arrays aren't equal, the message “Arrays should be equal” will be displayed as output.

4.2. assertEquals

In case we want to assert that two floats are equals, we can use the simple assertEquals assertion:

@Test public void whenAssertingEquality_thenEqual() { float square = 2 * 2; float rectangle = 2 * 2; assertEquals(square, rectangle); }

However, if we want to assert that the actual value differs by a predefined delta from the expected value, we can still use the assertEquals but we have to pass the delta value as the third parameter:

@Test public void whenAssertingEqualityWithDelta_thenEqual() { float square = 2 * 2; float rectangle = 3 * 2; float delta = 2; assertEquals(square, rectangle, delta); }

4.3. assertTrue and assertFalse

With the assertTrue assertion, it's possible to verify the supplied conditions are true:

@Test public void whenAssertingConditions_thenVerified() { assertTrue(5 > 4, "5 is greater the 4"); assertTrue(null == null, "null is equal to null"); }

Thanks to the support of the lambda expression, it's possible to supply a BooleanSupplier to the assertion instead of a boolean condition.

Let's see how we can assert the correctness of a BooleanSupplier using the assertFalse assertion:

@Test public void givenBooleanSupplier_whenAssertingCondition_thenVerified() { BooleanSupplier condition = () -> 5 > 6; assertFalse(condition, "5 is not greater then 6"); }

4.4. assertNull and assertNotNull

When we want to assert that an object is not null we can use the assertNotNull assertion:

@Test public void whenAssertingNotNull_thenTrue() { Object dog = new Object(); assertNotNull(dog, () -> "The dog should not be null"); }

In the opposite way, we can use the assertNull assertion to check if the actual is null:

@Test public void whenAssertingNull_thenTrue() { Object cat = null; assertNull(cat, () -> "The cat should be null"); }

In both cases, the failure message will be retrieved in a lazy way since it's a Supplier.

4.5. assertSame and assertNotSame

When we want to assert that the expected and the actual refer to the same Object, we must use the assertSame assertion:

@Test public void whenAssertingSameObject_thenSuccessfull() { String language = "Java"; Optional optional = Optional.of(language); assertSame(language, optional.get()); }

In the opposite way, we can use the assertNotSame one.

4.6. fail

The fail assertion fails a test with the provided failure message as well as the underlying cause. This can be useful to mark a test when it's development it's not completed:

@Test public void whenFailingATest_thenFailed() { // Test not completed fail("FAIL - test not completed"); }

4.7. assertAll

One of the new assertion introduced in JUnit 5 is assertAll.

This assertion allows the creation of grouped assertions, where all the assertions are executed and their failures are reported together. In details, this assertion accepts a heading, that will be included in the message string for the MultipleFailureError, and a Stream of Executable.

Let's define a grouped assertion:

@Test public void givenMultipleAssertion_whenAssertingAll_thenOK() { assertAll( "heading", () -> assertEquals(4, 2 * 2, "4 is 2 times 2"), () -> assertEquals("java", "JAVA".toLowerCase()), () -> assertEquals(null, null, "null is equal to null") ); }

The execution of a grouped assertion is interrupted only when one of the executables throws a blacklisted exception (OutOfMemoryError for example).

4.8. assertIterableEquals

The assertIterableEquals asserts that the expected and the actual iterables are deeply equal.

In order to be equal, both iterable must return equal elements in the same order and it isn't required that the two iterables are of the same type in order to be equal.

With this consideration, let's see how we can assert that two lists of different types (LinkedList and ArrayList for example) are equal:

@Test public void givenTwoLists_whenAssertingIterables_thenEquals() { Iterable al = new ArrayList(asList("Java", "Junit", "Test")); Iterable ll = new LinkedList(asList("Java", "Junit", "Test")); assertIterableEquals(al, ll); }

In the same way of the assertArrayEquals, if both iterables are null, they are considered equal.

4.9. assertLinesMatch

The assertLinesMatch asserts that the expected list of String matches the actual list.

This method differs from the assertEquals and assertIterableEquals since, for each pair of expected and actual lines, it performs this algorithm:

  1. check if the expected line is equal to the actual one. If yes it continues with the next pair
  2. treat the expected line as a regular expression and performs a check with the String.matches() method. If yes it continues with the next pair
  3. check if the expected line is a fast-forward marker. If yes apply fast-forward and repeat the algorithm from the step 1

Let's see how we can use this assertion to assert that two lists of String have matching lines:

@Test public void whenAssertingEqualityListOfStrings_thenEqual() { List expected = asList("Java", "\\d+", "JUnit"); List actual = asList("Java", "11", "JUnit"); assertLinesMatch(expected, actual); }

4.10. assertNotEquals

Complementary to the assertEquals, the assertNotEquals assertion asserts that the expected and the actual values aren't equal:

@Test public void whenAssertingEquality_thenNotEqual() { Integer value = 5; // result of an algorithm assertNotEquals(0, value, "The result cannot be 0"); }

If both are null, the assertion fails.

4.11. assertThrows

In order to increase simplicity and readability, the new assertThrows assertion allows us a clear and a simple way to assert if an executable throws the specified exception type.

Let's see how we can assert a thrown exception:

@Test void whenAssertingException_thenThrown() { Throwable exception = assertThrows( IllegalArgumentException.class, () -> { throw new IllegalArgumentException("Exception message"); } ); assertEquals("Exception message", exception.getMessage()); }

The assertion will fail if no exception is thrown, or if an exception of a different type is thrown.

4.12. assertTimeout and assertTimeoutPreemptively

In case we want to assert that the execution of a supplied Executable ends before a given Timeout, we can use the assertTimeout assertion:

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

However, with the assertTimeout assertion, the supplied executable will be executed in the same thread of the calling code. Consequently, execution of the supplier won't be preemptively aborted if the timeout is exceeded.

In case we want to be sure that execution of the executable will be aborted once it exceeds the timeout, we can use the assertTimeoutPreemptively assertion.

Beide Zusicherungen können anstelle einer ausführbaren Datei einen ThrowingSupplier akzeptieren, der einen generischen Codeblock darstellt, der ein Objekt zurückgibt und möglicherweise einen Throwable auslösen kann.

5. Schlussfolgerung

In diesem Tutorial haben wir alle Aussagen behandelt, die sowohl in JUnit 4 als auch in JUnit 5 verfügbar sind.

Wir haben kurz die Verbesserungen in JUnit 5 hervorgehoben, mit der Einführung neuer Behauptungen und der Unterstützung von Lambdas.

Wie immer ist der vollständige Quellcode für diesen Artikel auf GitHub verfügbar.