JUnit 5: Comment affirmer qu'une exception est levée?

215

Existe-t-il une meilleure façon d'affirmer qu'une méthode lève une exception dans JUnit 5?

Actuellement, je dois utiliser une @Rule afin de vérifier que mon test lève une exception, mais cela ne fonctionne pas dans les cas où je m'attends à ce que plusieurs méthodes lèvent des exceptions dans mon test.

steventrouble
la source
1
vous pourriez être intéressé de vérifier AssertJ pour vérifier les exceptions car il est plus flexible que JUnit5
user1075613

Réponses:

325

Vous pouvez utiliser assertThrows()ce qui vous permet de tester plusieurs exceptions dans le même test. Avec la prise en charge des lambdas dans Java 8, c'est la manière canonique de tester les exceptions dans JUnit.

Selon les documents JUnit :

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
la source
11
D'une vieille école "je ne sais pas grand chose sur Junit5 et probablement pas assez sur Java8" ... cela semble plutôt bizarre. Pourriez-vous ajouter quelques explications supplémentaires? comme "quelle partie du test est le" code de production "en cours de test ... qui serait censé être lancé"?
GhostCat
1
() -> pointe vers une expression lambda qui accepte zéro argument. Ainsi, le "code de production" qui devrait lever l'exception est dans le bloc de code pointé (c'est- à -dire l' throw new...instruction entre crochets).
Sam Brannen
1
Typiquement, l'expression lambda interagirait avec le sujet testé (SUT). En d'autres termes, lever directement une exception comme ci-dessus est juste à des fins de démonstration.
Sam Brannen
1
On dirait que expectThrows est obsolète. Les documents disent d'utiliser à la place assertThrows ().
depsypher
5
Depuis la version 5.0.0-M4, expectThrows n'est plus disponible. Seul assertThrows est autorisé. Voir github.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'Suppression de la méthode Assertions.expectThrows () supprimée en faveur de Assertions.assertThrows ()'
gil.fernandes
91

En Java 8 et JUnit 5 (Jupiter), nous pouvons affirmer les exceptions comme suit. En utilisantorg.junit.jupiter.api.Assertions.assertThrows

public statique <T étend Throwable> T assertThrows (Class <T> attenduType, exécutable exécutable)

Affirme que l'exécution de l'exécutable fourni lève une exception du type attendu et renvoie l'exception.

Si aucune exception n'est levée ou si une exception d'un type différent est levée, cette méthode échouera.

Si vous ne souhaitez pas effectuer de vérifications supplémentaires sur l'instance d'exception, ignorez simplement la valeur de retour.

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

Cette approche utilisera l'interface fonctionnelle Executabledans org.junit.jupiter.api.

Référer :

premier
la source
1
Au sommet avec celui-ci! C'est de loin la meilleure réponse qui soit la plus récente avec JUnit 5. De plus, IntelliJ réduit encore plus la lambda s'il n'y a qu'une seule ligne vers la Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932
26

Ils l'ont changé dans JUnit 5 (attendu: InvalidArgumentException, actual: méthode invoquée) et le code ressemble à celui-ci:

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

Maintenant Junit5 fournit un moyen d'affirmer les exceptions

Vous pouvez tester à la fois les exceptions générales et les exceptions personnalisées

Un scénario d'exception général:

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());
}

Vous pouvez trouver un exemple pour tester CustomException ici: affirmer l'exemple de code d'exception

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
la source
1
Il n'y a aucune différence dans la façon dont JUnit gère les exceptions intégrées et personnalisées.
raindev
9

Je pense que c'est un exemple encore plus simple

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

Faire appel get()à une option contenant un vide ArrayListlancera un NoSuchElementException. assertThrowsdéclare l'exception attendue et fournit un fournisseur lambda (ne prend aucun argument et renvoie une valeur).

Merci à @prime pour sa réponse que j'espère avoir développée.

JesseBoyd
la source
1
la méthode assertThrowsrenvoie l'exception levée. Vous pouvez donc faire comme NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());ci-dessous, vous pouvez faire toutes sortes d'assertions sur l'objet d'exception que vous souhaitez.
Captain Man
8

Vous pouvez utiliser assertThrows(). Mon exemple est tiré de la documentation 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
la source
2

Une doublure encore plus simple. Aucune expression lambda ou accolade n'est requise pour cet exemple utilisant Java 8 et JUnit 5

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
la source
1

En fait, je pense qu'il y a une erreur dans la documentation de cet exemple particulier. La méthode prévue est expectThrows

public static void assertThrows(
public static <T extends Throwable> T expectThrows(
Peter Isberg
la source
3
"Suppression de la méthode Assertions.expectThrows () obsolète au profit de Assertions.assertThrows ()."
Martin Schröder
Pour Junit 5, assurez-vous qu'il provient de org.junit.jupiter.api.Assertions et non org.testng.Assert. Notre projet comprend à la fois Junit et TestNG, et j'ai continué à recevoir assertThrows renvoie une erreur nulle jusqu'à ce que je le change en assertExpects. Il s'est avéré que j'utilisais org.testng.Assert.
barryku
-5

Voici un moyen simple.

@Test
void exceptionTest() {

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

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

}

Il ne réussit que lorsque l'exception que vous attendez est levée.

kiwicomb123
la source