JUnit 5: ¿Cómo hacer valer una excepción?

215

¿Hay una mejor manera de afirmar que un método arroja una excepción en JUnit 5?

Actualmente, tengo que usar una @Rule para verificar que mi prueba arroje una excepción, pero esto no funciona para los casos en los que espero que varios métodos arrojen excepciones en mi prueba.

steventrouble
fuente
1
es posible que le interese verificar AssertJ para verificar las excepciones, ya que es más flexible que JUnit5
user1075613

Respuestas:

325

Puede usar assertThrows(), lo que le permite probar múltiples excepciones dentro de la misma prueba. Con soporte para lambdas en Java 8, esta es la forma canónica de probar excepciones en JUnit.

Según los documentos de 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
fuente
11
De una vieja escuela "No sé mucho sobre Junit5 y probablemente no lo suficiente sobre Java8" ... esto parece bastante extraño. ¿Le importaría agregar algunas explicaciones más? como "¿qué parte de ahí está el 'código de producción' real bajo prueba ... que se supone que arrojará"?
GhostCat
1
() -> apunta a una expresión lambda que acepta cero argumentos. Por lo tanto, el "código de producción" que se espera que arroje la excepción está en el bloque de código señalado (es decir, la throw new...declaración dentro de las llaves).
Sam Brannen
1
Típicamente, la expresión lambda interactuaría con el sujeto bajo prueba (SUT). En otras palabras, lanzar directamente una excepción como la anterior es solo para fines de demostración.
Sam Brannen
1
Parece que expectThrows está en desuso. Los doctores dicen que ahora use aserciónThrows ().
depsypher
55
A partir de la versión 5.0.0-M4, waitThrows ya no está disponible. Solo afirmar Throws está permitido. Consulte github.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'Se eliminó el método obsoleto Assertions.expectThrows () a favor de Assertions.assertThrows ()'
gil.fernandes
91

En Java 8 y JUnit 5 (Júpiter) podemos afirmar excepciones de la siguiente manera. Utilizandoorg.junit.jupiter.api.Assertions.assertThrows

public static <T extend Throwable> T afirmarThrows (Clase <T >pectedType, Ejecutable ejecutable)

Afirma que la ejecución del ejecutable proporcionado genera una excepción del tipo esperado y devuelve la excepción.

Si no se lanza una excepción, o si se lanza una excepción de un tipo diferente, este método fallará.

Si no desea realizar verificaciones adicionales en la instancia de excepción, simplemente ignore el valor de retorno.

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

Ese enfoque utilizará la interfaz funcional Executableen org.junit.jupiter.api.

Referir:

principal
fuente
1
¡A la cima con este! Esta es la mejor respuesta, con mucho, la más actualizada con JUnit 5. Además, IntelliJ está condensando aún más la lambda si solo hay una línea para la Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932
26

Lo han cambiado en JUnit 5 (esperado: InvalidArgumentException, real: método invocado) y el código se ve así:

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

Ahora Junit5 proporciona una forma de hacer valer las excepciones.

Puede probar tanto las excepciones generales como las personalizadas.

Un escenario de excepción general:

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

Puede encontrar una muestra para probar CustomException aquí: afirmar una muestra de código de excepción

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
fuente
1
No hay diferencia en cómo JUnit maneja las excepciones integradas y personalizadas.
raindev
9

Creo que este es un ejemplo aún más simple

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

Llamar get()a un opcional que contiene un vacío ArrayListarrojará un NoSuchElementException. assertThrowsdeclara la excepción esperada y proporciona un proveedor lambda (no toma argumentos y devuelve un valor).

Gracias a @prime por su respuesta, que espero haber explicado.

JesseBoyd
fuente
1
El método assertThrowsdevuelve la excepción lanzada. Entonces puede hacer lo NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());siguiente, a continuación puede hacer cualquier tipo de aserciones sobre el objeto de excepción que desee.
Capitán Man
8

Puedes usar assertThrows(). Mi ejemplo está tomado de los documentos 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
fuente
2

Un forro aún más simple. No se requieren expresiones lambda o llaves para este ejemplo usando Java 8 y 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
fuente
1

En realidad, creo que hay un error en la documentación de este ejemplo en particular. El método que se pretende es esperar.

public static void assertThrows(
public static <T extends Throwable> T expectThrows(
Peter Isberg
fuente
3
"Se eliminó el método obsoleto Assertions.expectThrows () a favor de Assertions.assertThrows ()".
Martin Schröder
Para el 5 de junio, asegúrese de que sea de org.junit.jupiter.api.Assertions no de org.testng.Assert. Nuestro proyecto tiene Junit y TestNG incluidos, y seguí obteniendo afirmarThrows devuelve un error nulo hasta que lo cambié a afirmarExpectos. Resultó que estaba usando org.testng.Assert.
barryku
-5

Aquí hay una manera fácil.

@Test
void exceptionTest() {

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

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

}

Solo tiene éxito cuando se lanza la excepción que espera.

kiwicomb123
fuente