assertAll vs. mehrere Assertionen in JUnit5

Lesezeit: 5 Minuten

Benutzer-Avatar
Wilhelm Olejnik

Gibt es einen Grund, mehrere Behauptungen zu gruppieren:

public void shouldTellIfPrime(){
    Assertions.assertAll(
            () -> assertTrue(isPrime(2)),
            () -> assertFalse(isPrime(4))
    );
}

anstatt dies zu tun:

public void shouldTellIfPrime(){
    Assertions.assertTrue(isPrime(2));
    Assertions.assertFalse(isPrime(4));
}

Das Interessante daran assertAll ist es das prüft immer alle Assertions, die an ihn übergeben werden, egal wie viele scheitern. Wenn alle bestanden haben, ist alles in Ordnung – wenn mindestens einer fehlschlägt, erhalten Sie ein detailliertes Ergebnis von allem, was schief gelaufen ist (und übrigens richtig).

Es wird am besten verwendet, um eine Reihe von Eigenschaften zu behaupten, die konzeptionell zusammengehören. Etwas, bei dem Ihr erster Instinkt wäre: “Ich möchte dies als einen behaupten”.

Beispiel

Ihr spezifisches Beispiel ist kein optimaler Anwendungsfall für assertAll weil prüfen isPrime mit einer Primzahl und einer Nicht-Primzahl ist unabhängig voneinander – so sehr, dass ich empfehlen würde, dafür zwei Testmethoden zu schreiben.

Aber nehmen Sie an, Sie haben eine einfache Klasse wie eine Adresse mit Feldern city, street, number und möchte versichern, dass dies das ist, was Sie von ihnen erwarten:

Address address = unitUnderTest.methodUnderTest();
assertEquals("Redwood Shores", address.getCity());
assertEquals("Oracle Parkway", address.getStreet());
assertEquals("500", address.getNumber());

Sobald die erste Assertion fehlschlägt, werden Sie die Ergebnisse der zweiten nie sehen, was ziemlich ärgerlich sein kann. Es gibt viele Möglichkeiten, dies und den von JUnit Jupiter zu umgehen assertAll Ist einer von ihnen:

Address address = unitUnderTest.methodUnderTest();
assertAll("Should return address of Oracle's headquarter",
    () -> assertEquals("Redwood Shores", address.getCity()),
    () -> assertEquals("Oracle Parkway", address.getStreet()),
    () -> assertEquals("500", address.getNumber())
);

Wenn die zu testende Methode die falsche Adresse zurückgibt, erhalten Sie die folgende Fehlermeldung:

org.opentest4j.MultipleFailuresError:
    Should return address of Oracle's headquarter (3 failures)
    expected: <Redwood Shores> but was: <Walldorf>
    expected: <Oracle Parkway> but was: <Dietmar-Hopp-Allee>
    expected: <500> but was: <16>

  • Aber missbrauchen Sie es nicht! Eine einzelne Testmethode sollte immer testen nur eine Annahme über den Produktionscode. Das ist der Hauptgrund, warum Sie normalerweise nur ein Assertion pro Testmethode haben.

    – Timothy Truckle

    25. November 2016 um 16:57 Uhr

  • Ich stimme zu, es nicht zu missbrauchen und nur eine Annahme zu testen, aber nicht damit, dass es irgendeinen Wert hat, Behauptungen zu zählen. Das ist eine rein syntaktische Betrachtung ohne Relevanz. Nehmen Sie mein Beispiel: Die Chancen stehen gut Address:equals testet genau diese Eigenschaften, in diesem Fall könnte ich sie mit einer Behauptung verifizieren. Logischerweise gäbe es überhaupt keinen Unterschied, aber plötzlich ist es “nur eine Behauptung”. Das Gleiche gilt, wenn ich mir die Mühe mache, einen Hamcrest-Matcher für die Klasse zu erstellen.

    – Nicolai Parlog

    25. November 2016 um 21:46 Uhr

  • “aber bin nicht damit einverstanden, dass es irgendeinen Wert hat, Behauptungen zu zählen” Ich habe nicht vorgeschlagen, Behauptungen zu “zählen”. ein Assertion pro Testmethode ist eine Faustregel, nicht mehr, aber auch nicht weniger… Wie auch immer, wenn Sie mehrere Asserts haben, sollten Sie sich fragen, ob Sie wirklich Tests testen einzige Annahme.

    – Timothy Truckle

    26. November 2016 um 19:25 Uhr


  • Ich stimme der Faustregel “Ein Test, eine Aussage” nicht ganz zu. Es wird davon ausgegangen, dass der zu testende Code schnell und einfach auszuführen ist. Da Ihre Tests von Komponententests auf niedriger Ebene zu Integrationstests auf hoher Ebene skalieren, gilt diese Annahme nicht. Es ist viel effizienter, einen teuren Code einmal auszuführen und mehrere kostengünstige Assertionen auf die Ergebnisse anzuwenden, anstatt den teuren Code mehrmals auszuführen und jedes Mal eine Sache zu testen. Zusicherungen an Zwischenpunkten können auch beim Debuggen helfen. Solange Sie Behauptungen eindeutig kennzeichnen, ist es kein Problem, mehrere zu verwenden.

    – P. Jeremy Krieg

    7. März 2019 um 3:06 Uhr

Benutzer-Avatar
Nkosi

Laut Dokumentation hier

Bestätigt, dass alle bereitgestellten ausführbaren Dateien keinen AssertionError auslösen.

Wenn eine bereitgestellte ausführbare Datei einen AssertionError auslöst, werden alle verbleibenden ausführbaren Dateien trotzdem ausgeführt, und alle Fehler werden aggregiert und in einem MultipleFailuresError gemeldet. Wenn jedoch eine ausführbare Datei eine Ausnahme auslöst, die kein AssertionError ist, wird die Ausführung sofort angehalten, und die Ausnahme wird unverändert erneut ausgelöst, jedoch als ungeprüfte Ausnahme maskiert.

Der Hauptunterschied besteht also darin, dass die behauptenAlle wird es allen Asserts ermöglichen, ausgeführt zu werden, ohne den Fluss zu unterbrechen, während die anderen mögen behauptenWahr und das Los wird den Test mit dem stoppen Behauptungsfehler

In Ihrem ersten Beispiel werden also beide Assertionen unabhängig von Pass to Fail ausgeführt, während im zweiten Beispiel der Test beendet wird, wenn die erste Assertion fehlschlägt.

Gibt es einen Grund, mehrere Behauptungen zu gruppieren?

Wenn Sie möchten, dass alle Behauptungen im Komponententest ausgeführt werden.

assert und assertAllsind beide Methoden darauf ausgelegt, die erwartete Ausgabe im Vergleich zur tatsächlichen Ausgabe zu validieren.

Einfach gesagt assertwenn die erste Assertion fehlschlägt, schlägt der gesamte Testfall fehl und die restlichen Asserts werden nicht validiert. assertAll validiert alle Testfälle.

Wenn einige Behauptungen fehlschlagen, wird es auch den Rest der Behauptungen fortsetzen und das Validierungsergebnis für alle fehlgeschlagenen Behauptungen zurückgeben.

Zum Beispiel:

public Apple addApple(int appleId, String appleName) {
    Apple apple = new Apple(appleId, appleName);
    return apple;
}

Testfall:

@Test
void addAppleAssertTest() {
    System.out.println("AppleCalculatorTest.addAppleTest");
    AppleCalculator appleCalculator = new AppleCalculator();
    Apple apple = appleCalculator.addApple(1, "apple");
    assertNotNull(apple, "apple object should not be null");
    assertEquals(11, apple.getAppleId(), "appleId should be 1");
    assertEquals("apple1", apple.getAppleName(), "appleName should be apple");
}
    
@Test
void addAppleAssertAllTest() {
    System.out.println("AppleCalculatorTest.addAppleTest");
    AppleCalculator appleCalculator = new AppleCalculator();
    Apple apple = appleCalculator.addApple(1, "apple");
    assertAll(() -> assertNotNull(apple, "apple object should not be null"),
        () -> assertEquals(11, apple.getAppleId(), "appleId should be 1"),
        () -> assertEquals("apple1", apple.getAppleName(), "appleName should be apple"));
}

  • Was haben Sie zu den vorhandenen Antworten hinzugefügt?

    – Ilya Serbis

    22. Juli um 21:29 Uhr

1277450cookie-checkassertAll vs. mehrere Assertionen in JUnit5

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy