Mockito Comment se moquer et affirmer une exception lancée?

136

J'utilise mockito dans un test junit. Comment faire pour qu'une exception se produise et ensuite affirmer qu'elle a (pseudo-code générique)

stackoverflow
la source

Réponses:

75

Solution de style BDD (mise à jour vers Java 8)

Mockito seul n'est pas la meilleure solution pour gérer les exceptions, utilisez Mockito avec Catch-Exception

Mockito + Catch-Exception + AssertJ

given(otherServiceMock.bar()).willThrow(new MyException());

when(() -> myService.foo());

then(caughtException()).isInstanceOf(MyException.class);

Exemple de code

Dépendances

MariuszS
la source
2
Qu'est-ce que "catch-exception"? Vous avez un lien?
Duncan Jones
quoi caughtException?
Saif Masadeh
OK, ça vient decom.googlecode.catchexception.CatchException.caughtException;
Saif Masadeh
212

Pour répondre d'abord à votre deuxième question. Si vous utilisez JUnit 4, vous pouvez annoter votre test avec

@Test(expected=MyException.class)

pour affirmer qu'une exception s'est produite. Et pour "simuler" une exception avec mockito, utilisez

when(myMock.doSomething()).thenThrow(new MyException());
NilsH
la source
2
cette approche est inacceptable pour le cas où vous testez la méthode d'un objet qui a un état. Par exemple, il existe une méthode objet qui lève une exception si vous l'appelez la deuxième fois. Et vous devez tester pour vérifier qu'il lève une exception lors du deuxième appel de méthode, pas du premier. S'il lève MyException lors du premier appel de méthode (dans la phase de préparation), le test doit échouer. Mais avec cette approche, nous ne sommes pas en mesure de vérifier pendant quel appel de méthode l'exception est lancée.
Sneg
Bien que dans ce cas, nous pouvons intercepter l'exception du premier appel de méthode et l'encapsuler dans RuntimeException.
Sneg
29

Si vous souhaitez également tester le message d'exception, vous pouvez utiliser ExpectedException de JUnit avec Mockito:

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testExceptionMessage() throws Exception {
    expectedException.expect(AnyException.class);
    expectedException.expectMessage("The expected message");

    given(foo.bar()).willThrow(new AnyException("The expected message"));
}
Daniel Treiber
la source
given()D'où est-ce que ça vient?
Mohammad Faisal
Je préfère également utiliser la @Rule, car de cette façon, je peux tester le message attendu, la cause ou d'autres éléments relatifs à l'exception. Pour vérifier la cause de l'exception, j'utilise: expectedException.expectCause (Mockito.sameInstance (expectedException)) ou expectedException.expectCause (Mockito.instanceOf (MyException.class)) et quelques autres qui sont utiles.
Crenguta S
19

Réponse mise à jour pour le 19/06/2015 (si vous utilisez java 8)

Utilisez simplement assertj

Utilisation d'assertj-core-3.0.0 + Java 8 Lambdas

@Test
public void shouldThrowIllegalArgumentExceptionWhenPassingBadArg() {
assertThatThrownBy(() -> myService.sumTingWong("badArg"))
                                  .isInstanceOf(IllegalArgumentException.class);
}

Référence: http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html

Selwyn
la source
a fonctionné pour moi ... Nous pouvons également vérifier le message d'exception.assertThatThrownBy (() -> myService.sumTingWong ("badArg")). hasMessage ("test") .isInstanceOf (IllegalArgumentException.class);
Sritam Jagadev
17

Si vous utilisez JUnit 4 et Mockito 1.10.x Annotez votre méthode de test avec:

@Test(expected = AnyException.class)

et pour lancer votre exception, utilisez:

Mockito.doThrow(new AnyException()).when(obj).callAnyMethod();
Prashant Kumar
la source
16

Faites que l'exception se produise comme ceci:

when(obj.someMethod()).thenThrow(new AnException());

Vérifiez que cela s'est produit soit en affirmant que votre test lèvera une telle exception:

@Test(expected = AnException.class)

Ou par une vérification simulée normale:

verify(obj).someMethod();

Cette dernière option est requise si votre test est conçu pour prouver que le code intermédiaire gère l'exception (c'est-à-dire que l'exception ne sera pas levée depuis votre méthode de test).

Duncan Jones
la source
L' verifyappel affirme-t-il l'exception?
NilsH
@NilsH Non. Mais à condition que la whenclause soit correcte, elle doit avoir levé une exception.
Duncan Jones
10

Utilisez doThrow de Mockito , puis attrapez l'exception souhaitée pour affirmer qu'elle a été levée plus tard.

@Test
public void fooShouldThrowMyException() {
    // given
    val myClass = new MyClass();
    val arg = mock(MyArgument.class);
    doThrow(MyException.class).when(arg).argMethod(any());
    Exception exception = null;

    // when
    try {
        myClass.foo(arg);
    } catch (MyException t) {
        exception = t;
    }

    // then
    assertNotNull(exception);
}
Rodrigo Martins de Oliveira
la source
5

En utilisant mockito, vous pouvez faire en sorte que l'exception se produise.

when(testingClassObj.testSomeMethod).thenThrow(new CustomException());

En utilisant Junit5, vous pouvez affirmer une exception, affirmer si cette exception est levée lors de l' appel de la méthode de test .

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

Trouvez un exemple ici: assert exception junit

Anupama Boorlagadda
la source
Merci ! A travaillé pour moi
HariKishore
1

Sans rapport avec mockito, on peut attraper l'exception et affirmer ses propriétés. Pour vérifier que l'exception s'est produite, déclarez une condition fausse dans le bloc try après l'instruction qui lève l'exception.

anguille ghEEz
la source
La réponse @MariuszS répond correctement à ce que vous dites n'est pas lié à Mockito
pringi
@pringi Merci, je vois que la question concernait à la fois se moquer d'une exception et l'attraper. Je me demande cependant si cela dépend du comportement du code testé.
eel ghEEz
1

Ou si votre exception est levée depuis le constructeur d'une classe:

@Rule
public ExpectedException exception = ExpectedException.none();

@Test
public void myTest() {    

    exception.expect(MyException.class);
    CustomClass myClass= mock(CustomClass.class);
    doThrow(new MyException("constructor failed")).when(myClass);  

}
JediCate
la source
-1

Message d'affirmation par exception:

    try {
        MyAgent.getNameByNode("d");
    } catch (Exception e) {
        Assert.assertEquals("Failed to fetch data.", e.getMessage());
    }
Sam
la source
S'il est écrit comme ceci, quand il n'y a pas d' exception levée, le test réussira toujours . C'est ce que nous voulons éviter en premier lieu
Christian Lim