JUnit 5: Wie wird eine Ausnahme ausgelöst?

214

Gibt es eine bessere Möglichkeit zu behaupten, dass eine Methode in JUnit 5 eine Ausnahme auslöst?

Derzeit muss ich eine @Rule verwenden, um zu überprüfen, ob mein Test eine Ausnahme auslöst. Dies funktioniert jedoch nicht in den Fällen, in denen ich erwarte, dass mehrere Methoden Ausnahmen in meinem Test auslösen.

steventrouble
quelle
1
Möglicherweise möchten Sie AssertJ überprüfen, um Ausnahmen zu überprüfen. Es ist flexibler als JUnit5
user1075613

Antworten:

321

Sie können verwenden assertThrows(), um mehrere Ausnahmen innerhalb desselben Tests zu testen. Mit der Unterstützung von Lambdas in Java 8 ist dies die kanonische Methode zum Testen auf Ausnahmen in JUnit.

Gemäß den JUnit-Dokumenten :

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

@Test
void exceptionTesting() {
    MyException thrown = assertThrows(
           MyException.class,
           () -> myObject.doThing(),
           "Expected doThing() to throw, but it didn't"
    );

    assertTrue(thrown.getMessage().contains("Stuff"));
}
steventrouble
quelle
11
Aus einer alten Schule "Ich weiß nicht viel über Junit5 und wahrscheinlich nicht genug über Java8" ... das sieht ziemlich bizarr aus. Würde es Ihnen etwas ausmachen, weitere Erklärungen hinzuzufügen? wie "Welcher Teil enthält den eigentlichen 'Produktionscode', der getestet wird ... der eigentlich geworfen werden sollte"?
GhostCat
1
() -> zeigt auf einen Lambda-Ausdruck, der keine Argumente akzeptiert. Somit befindet sich der "Produktionscode", von dem erwartet wird, dass er die Ausnahme auslöst, in dem Codeblock, auf den verwiesen wird (dh die throw new...Anweisung in den geschweiften Klammern).
Sam Brannen
1
Typischerweise interagiert der Lambda-Ausdruck mit dem zu testenden Subjekt (SUT). Mit anderen Worten, das direkte Auslösen einer Ausnahme wie oben dient nur zu Demonstrationszwecken.
Sam Brannen
1
Es sieht so aus, als ob expectedThrows veraltet ist. Die Ärzte sagen, dass sie jetzt stattdessen assertThrows () verwenden sollen.
Depsypher
5
Ab Version 5.0.0-M4 ist expectedThrows nicht mehr verfügbar. Nur assertThrows ist erlaubt. Siehe github.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'Veraltete Assertions.expectThrows () -Methode zugunsten von Assertions.assertThrows ()' entfernt
gil.fernandes
91

In Java 8 und JUnit 5 (Jupiter) können wir Ausnahmen wie folgt geltend machen. Verwenden vonorg.junit.jupiter.api.Assertions.assertThrows

public static <T erweitert Throwable> T assertThrows (Klasse <T> expectedType, ausführbare ausführbare Datei)

Gibt an, dass die Ausführung der angegebenen ausführbaren Datei eine Ausnahme des erwarteten Typs auslöst und die Ausnahme zurückgibt.

Wenn keine Ausnahme ausgelöst wird oder wenn eine Ausnahme eines anderen Typs ausgelöst wird, schlägt diese Methode fehl.

Wenn Sie keine zusätzlichen Überprüfungen für die Ausnahmeinstanz durchführen möchten, ignorieren Sie einfach den Rückgabewert.

@Test
public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
    assertThrows(NullPointerException.class,
            ()->{
            //do whatever you want to do here
            //ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
            });
}

Dieser Ansatz verwendet die Funktionsschnittstelle Executablein org.junit.jupiter.api.

Verweisen :

Prime
quelle
1
Mit diesem nach oben! Dies ist bei weitem die beste Antwort, die mit JUnit 5 am aktuellsten ist. Außerdem verdichtet IntelliJ das Lambda noch weiter, wenn es nur eine Zeile zum Lambda gibt:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932
26

Sie haben es in JUnit 5 geändert (erwartet: InvalidArgumentException, tatsächliche: aufgerufene Methode) und der Code sieht folgendermaßen aus:

@Test
public void wrongInput() {
    Throwable exception = assertThrows(InvalidArgumentException.class,
            ()->{objectName.yourMethod("WRONG");} );
}
jstar
quelle
21

Jetzt bietet Junit5 eine Möglichkeit, die Ausnahmen geltend zu machen

Sie können sowohl allgemeine als auch benutzerdefinierte Ausnahmen testen

Ein allgemeines Ausnahmeszenario:

ExpectGeneralException.java

public void validateParameters(Integer param ) {
    if (param == null) {
        throw new NullPointerException("Null parameters are not allowed");
    }
}

ExpectGeneralExceptionTest.java

@Test
@DisplayName("Test assert NullPointerException")
void testGeneralException(TestInfo testInfo) {
    final ExpectGeneralException generalEx = new ExpectGeneralException();

     NullPointerException exception = assertThrows(NullPointerException.class, () -> {
            generalEx.validateParameters(null);
        });
    assertEquals("Null parameters are not allowed", exception.getMessage());
}

Ein Beispiel zum Testen von CustomException finden Sie hier: Beispiel für einen Ausnahmecode

ExpectCustomException.java

public String constructErrorMessage(String... args) throws InvalidParameterCountException {
    if(args.length!=3) {
        throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
    }else {
        String message = "";
        for(String arg: args) {
            message += arg;
        }
        return message;
    }
}

ExpectCustomExceptionTest.java

@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
    final ExpectCustomException expectEx = new ExpectCustomException();

     InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
            expectEx.constructErrorMessage("sample ","error");
        });
    assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}
Anupama Boorlagadda
quelle
1
Es gibt keinen Unterschied, wie JUnit integrierte und benutzerdefinierte Ausnahmen behandelt.
raindev
9

Ich denke, das ist ein noch einfacheres Beispiel

List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());

Wenn Sie get()ein optionales Element mit einem Leerzeichen ArrayListaufrufen, wird a ausgelöst NoSuchElementException. assertThrowsdeklariert die erwartete Ausnahme und stellt einen Lambda-Lieferanten bereit (nimmt keine Argumente entgegen und gibt einen Wert zurück).

Vielen Dank an @prime für seine Antwort, die ich hoffentlich ausgearbeitet habe.

JesseBoyd
quelle
1
Die Methode assertThrowsgibt die ausgelöste Ausnahme zurück. Sie können also wie NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());folgt vorgehen und beliebige Zusicherungen für das gewünschte Ausnahmeobjekt vornehmen.
Captain Man
8

Sie können verwenden assertThrows(). Mein Beispiel stammt aus den Dokumenten http://junit.org/junit5/docs/current/user-guide/

import org.junit.jupiter.api.Test;

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

....

@Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}
Will Humphreys
quelle
2

Ein noch einfacherer Einzeiler. Für dieses Beispiel sind unter Verwendung von Java 8 und JUnit 5 keine Lambda-Ausdrücke oder geschweiften Klammern erforderlich

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

@Test
void exceptionTesting() {

    assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails..."); 

// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}
rnyunja
quelle
1

Eigentlich denke ich, dass es einen Fehler in der Dokumentation für dieses spezielle Beispiel gibt. Die beabsichtigte Methode ist expectedThrows

public static void assertThrows(
public static <T extends Throwable> T expectThrows(
Peter Isberg
quelle
3
"Veraltete Assertions.expectThrows () -Methode zugunsten von Assertions.assertThrows () entfernt."
Martin Schröder
Stellen Sie für Junit 5 sicher, dass es von org.junit.jupiter.api.Assertions stammt, nicht von org.testng.Assert. In unserem Projekt sind sowohl Junit als auch TestNG enthalten, und ich habe immer wieder assertThrows-Rückgabefehler erhalten, bis ich es in assertExpects geändert habe. Es stellte sich heraus, dass ich org.testng.Assert verwendete.
Barryku
-5

Hier ist ein einfacher Weg.

@Test
void exceptionTest() {

   try{
        model.someMethod("invalidInput");
        fail("Exception Expected!");
   }
   catch(SpecificException e){

        assertTrue(true);
   }
   catch(Exception e){
        fail("wrong exception thrown");
   }

}

Dies ist nur erfolgreich, wenn die erwartete Ausnahme ausgelöst wird.

kiwicomb123
quelle