Mockito ¿Cómo burlarse y afirmar una excepción lanzada?

136

Estoy usando mockito en una prueba de junit. ¿Cómo hacer que ocurra una excepción y luego afirmar que tiene (pseudocódigo genérico)

desbordamiento de pila
fuente

Respuestas:

75

Solución de estilo BDD (actualizada a Java 8)

Mockito por sí solo no es la mejor solución para manejar excepciones, use Mockito con Catch-Exception

Mockito + Catch-Exception + AssertJ

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

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

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

Código de muestra

Dependencias

MariuszS
fuente
2
¿Qué es "excepción de captura"? ¿Tienes un enlace?
Duncan Jones el
lo que es caughtException?
Saif Masadeh
Lo tengo, viene decom.googlecode.catchexception.CatchException.caughtException;
Saif Masadeh
212

Para responder a su segunda pregunta primero. Si está usando JUnit 4, puede anotar su prueba con

@Test(expected=MyException.class)

para afirmar que ha ocurrido una excepción. Y para "burlarse" de una excepción con mockito, use

when(myMock.doSomething()).thenThrow(new MyException());
NilsH
fuente
2
este enfoque es inaceptable para el caso cuando está probando el método de un objeto que tiene algún estado. Por ejemplo, hay un método de objeto que arroja una excepción si lo llama por segunda vez. Y debe probar para comprobar que arroja una excepción durante la segunda llamada al método, no la primera. Si arroja MyException durante la primera llamada al método (en la etapa de preparación), entonces debe fallar la prueba. Pero con este enfoque no podemos verificar durante qué método se produce la llamada a la excepción.
Sneg
Aunque, en este caso, podemos detectar la excepción de la primera llamada al método y envolverla en RuntimeException.
Sneg
29

Si también desea probar el mensaje de excepción, puede usar ExpectedException de JUnit con 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
fuente
given()¿De donde viene esto?
Mohammad Faisal
También prefiero usar la @Rule, porque de esta manera puedo probar el mensaje esperado o la causa u otras cosas relacionadas con la excepción. Para verificar la causa de la excepción, uso: expectException.expectCause (Mockito.sameInstance (pectedException)) opectedException.expectCause (Mockito.instanceOf (MyException.class)) y algunos otros que son útiles.
Crenguta S
19

Respuesta actualizada para 19/06/2015 (si está utilizando Java 8)

Solo usa afirmar

Usando afirj-core-3.0.0 + Java 8 Lambdas

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

Referencia: http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html

Selwyn
fuente
funcionó para mí ... También podemos verificar el mensaje de excepción también.
Sritam Jagadev
17

Si usa JUnit 4 y Mockito 1.10.x Anote su método de prueba con:

@Test(expected = AnyException.class)

y para lanzar su excepción deseada use:

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

Haz que la excepción suceda así:

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

Verifique que haya sucedido ya sea afirmando que su prueba arrojará tal excepción:

@Test(expected = AnException.class)

O por verificación simulada normal:

verify(obj).someMethod();

La última opción es necesaria si su prueba está diseñada para probar que el código intermedio maneja la excepción (es decir, la excepción no se lanzará desde su método de prueba).

Duncan Jones
fuente
¿La verifyllamada afirma la excepción?
NilsH
@NilsH No. Pero siempre que la whencláusula sea correcta, debe haber arrojado una excepción.
Duncan Jones el
10

Use doThrow de Mockito y luego capture la excepción deseada para afirmar que se lanzó más tarde.

@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
fuente
5

Usando mockito, puedes hacer que la excepción suceda.

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

Usando Junit5, puede afirmar una excepción, afirma si esa excepción se produce cuando se invoca el método de prueba .

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

Encuentre una muestra aquí: afirmar excepción junit

Anupama Boorlagadda
fuente
Gracias ! Trabajó para mí
HariKishore
1

Sin relación con mockito, uno puede atrapar la excepción y afirmar sus propiedades. Para verificar que la excepción sucedió, afirme una condición falsa dentro del bloque try después de la declaración que arroja la excepción.

anguila ghEEz
fuente
La respuesta de @MariuszS responde correctamente lo que usted dice que no está relacionado con Mockito
pringi
@pringi Gracias, veo que la pregunta se refería tanto a burlarse de una excepción como a captarla. Sin embargo, me pregunto si esto depende de cualquier comportamiento del código bajo prueba.
anguila ghEEz
1

O si su excepción se produce desde el constructor de una clase:

@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
fuente
-1

Afirmar por mensaje de excepción:

    try {
        MyAgent.getNameByNode("d");
    } catch (Exception e) {
        Assert.assertEquals("Failed to fetch data.", e.getMessage());
    }
Sam
fuente
Si se escribe así, cuando no se produce una excepción, la prueba aún pasará . Que es lo que queremos evitar en primer lugar
Christian Lim