Cómo hacer tests de excepciones en JUnit 5 con assertThrows

Otros asertos de utilidad de JUnit 5 son assertThrows() y assertDoesNotThrow(), con los que podemos probar el lanzamiento de excepciones (o la ausencia de excepciones) en una pieza de código, aprovechándonos de las funciones lambda que tiene el lenguaje de programación Java desde la versión JDK 8. En este vídeo te cuento un ejemplo de cómo aplicarlo.

En el desarrollo de pruebas unitarias con JUnit 5, validar que se lancen excepciones específicas es una tarea mucho más sencilla y elegante que en versiones anteriores. Esto se debe a que JUnit 5 aprovecha las funciones lambda de Java para permitirnos escribir asertos claros y concisos que comprueban si un método lanza o no una excepción esperada.

Para ilustrar este enfoque, partimos de una interfaz llamada Pagable, que define un método para realizar pagos sobre un pedido. Este método recibe un proveedor de pagos, que es el encargado de ejecutar la operación. En caso de que algo falle, se lanza una excepción específica llamada PagoExcepción.

Contamos con dos implementaciones de esta interfaz ProveedorPago. La primera, PaypalProveedor, simula un proveedor que siempre funciona correctamente, sin lanzar errores. La segunda, SinFondos, representa un proveedor que siempre falla al intentar realizar un pago, lanzando la excepción PagoExcepción para indicar que no hay fondos suficientes.

Cuando ejecutamos pruebas que simplemente llaman a estos proveedores sin ningún tipo de control, la prueba con PaypalProveedor pasa sin problemas, pero la que usa SinFondos falla abruptamente porque la excepción no está siendo gestionada ni esperada en el test.

Aquí es donde entra en juego el método assertThrows de JUnit 5. Con él, podemos indicar explícitamente que esperamos que se lance una excepción determinada al ejecutar un bloque de código. Este bloque se pasa como una lambda que contiene la llamada al método que debería lanzar la excepción. Por ejemplo, para comprobar que al pagar con SinFondos se lanza la excepción PagoExcepción, escribiríamos algo así:

PagoExcepción exception = assertThrows(PagoExcepción.class, () -> {
    p.pagar();
});

Además, podemos capturar la excepción lanzada para realizar comprobaciones adicionales, como verificar el mensaje de error que contiene. Esto nos permite asegurarnos de que la excepción no solo se lanza, sino que también transmite la información correcta. Por ejemplo:

assertEquals("no tiene fondos para pagar", exception.getMessage());

Por otro lado, JUnit 5 también nos ofrece el método assertDoesNotThrow, que sirve para confirmar que un bloque de código se ejecuta sin lanzar ninguna excepción. Esto es útil para validar que ciertas operaciones se realizan correctamente y sin errores inesperados. Su uso es similar, pasando una lambda con el código a ejecutar:

assertDoesNotThrow(() -> {
    p.pagar();
});

Un detalle interesante es que, al usar estas funciones lambda, podemos prescindir de declarar throws en la firma de los métodos de prueba, ya que las excepciones quedan manejadas dentro de los asertos.

Para comprobar el comportamiento de nuestros tests, podemos invertir los proveedores en las pruebas: usar SinFondos donde esperábamos que no fallara y PaypalProveedor donde esperábamos una excepción. Esto nos mostrará claramente cómo los tests fallan con mensajes específicos, indicando si se esperaba una excepción que no ocurrió o si apareció una excepción inesperada.

En definitiva, con assertThrows y assertDoesNotThrow en JUnit 5, escribir tests que validan excepciones se vuelve un proceso mucho más cómodo, legible y robusto, aprovechando las ventajas que nos ofrecen las expresiones lambda en Java.

Lista de reproducción
  1. 1
    ¿Qué es una prueba unitaria? ¿Me vale con crear un main?
    7 minutos
  2. 2
    Cómo crear tests unitarios con JUnit 5
    17 minutos
  3. 3
    Cómo usar BeforeEach, AfterEach, BeforeAll y AfterAll en JUnit 5
    11 minutos
  4. 4
    Cómo cambiar el orden de los tests de JUnit 5 (aunque no deberías)
    8 minutos
  5. 5
    Cómo aprovechar la clase Assertions de JUnit 5
    8 minutos
  6. 6
    Cómo ejecutar tests condicionalmente en JUnit 5
    7 minutos
  7. 7
    Cómo hacer tests de excepciones en JUnit 5 con assertThrows
    5 minutos
  8. 8
    Cómo crear Nested tests en JUnit 5 (un test dentro de otro)
    5 minutos
  9. 9
    Cómo configurar y crear tests de JUnit 5 en NetBeans
    6 minutos
  10. 10
    Cómo configurar y crear tests de JUnit 5 en Eclipse
    5 minutos
  11. 11
    Cómo configurar y crear tests de JUnit 5 en IntelliJ IDEA
    4 minutos