CodeGym /Cursos /Módulo 5. Spring /Lección 132: Unit-tests usando JUnit 5

Lección 132: Unit-tests usando JUnit 5

Módulo 5. Spring
Nivel 9 , Lección 1
Disponible

Hoy vamos a ver los fundamentos de las pruebas Unit usando JUnit 5.

Vamos a ver cómo usar ese poder para crear código de calidad y seguro.

¿Qué es JUnit 5 y para qué sirve?

JUnit 5 — es la versión moderna del popular framework de testing para Java. Su objetivo es ayudar a los desarrolladores a escribir pruebas Unit de calidad. La ventaja de JUnit 5 está en su modularidad y flexibilidad. Estos son los componentes principales de JUnit 5:

  • JUnit Platform: se encarga de ejecutar los tests.
  • JUnit Jupiter: provee nuevas funcionalidades y anotaciones para testing.
  • JUnit Vintage: permite ejecutar tests antiguos escritos con JUnit 3 y 4 (arqueólogos, esto es para vosotros).

¿Por qué JUnit 5? Porque:

  • Soporta Java 8 y superiores, incluyendo lambdas y métodos por defecto.
  • Más posibilidades para configurar el ciclo de vida de los tests.
  • La anotación @DisplayName es superútil para que tus tests queden bonitos y claros.

Anotaciones principales de JUnit 5

Las anotaciones son como señales para JUnit, que le dicen qué y cómo testear.

@Test

La anotación más importante. Si quieres que un método se ejecute como test, márcalo con esta anotación.


import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

class MathTest {

    @Test
    void additionTest() {
        int result = 2 + 3;
        assertEquals(5, result, "2 + 3 debe ser igual a 5");
    }
}

@BeforeEach y @AfterEach

Se usan para ejecutar acciones antes y después de cada test. Por ejemplo, preparar el entorno de test o limpiar recursos.


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;

class LifecycleTest {

    @BeforeEach
    void setUp() {
        System.out.println("Preparación antes del test");
    }

    @AfterEach
    void tearDown() {
        System.out.println("Limpieza después del test");
    }

    @Test
    void simpleTest() {
        System.out.println("Ejecución del test");
    }
}

Las salidas serán así:


Preparación antes del test
Ejecución del test
Limpieza después del test

@BeforeAll y @AfterAll

Se usan para ejecutar acciones antes o después de todos los tests en la clase. Esos métodos deben ser estáticos.


import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;

class GlobalSetupTest {

    @BeforeAll
    static void init() {
        System.out.println("Preparación antes de TODOS los tests");
    }

    @AfterAll
    static void cleanup() {
        System.out.println("Limpieza después de TODOS los tests");
    }

    @Test
    void testOne() {
        System.out.println("Primer test");
    }

    @Test
    void testTwo() {
        System.out.println("Segundo test");
    }
}

Salida:


Preparación antes de TODOS los tests
Primer test
Segundo test
Limpieza después de TODOS los tests

@DisplayName

¡Añade un poco de vida al desierto digital de tus tests! Hazlos más bonitos con @DisplayName.

@Test
@DisplayName("Comprobación de la suma: 2 + 2 = 4")
void additionTest() {
    assertEquals(4, 2 + 2);
}

Assertions principales

Las Assertions son como checkpoints. Comprueban si tu código funciona correctamente.

Assertion Descripción Ejemplo
assertEquals(expected, actual) Comprueba si el valor esperado y el valor real son iguales assertEquals(4, 2 + 2)
assertNotEquals(unexpected, actual) Comprueba que los valores NO son iguales assertNotEquals(5, 2 + 2)
assertTrue(condition) Asegura que la condición es true assertTrue(2 + 2 == 4)
assertFalse(condition) Asegura que la condición es false assertFalse(2 + 2 == 5)
assertNull(object) Comprueba que el objeto es null assertNull(nullVariable)
assertNotNull(object) Comprueba que el objeto NO es null assertNotNull(nonNullVariable)
assertThrows(exception, lambda) Comprueba que el código lanza la excepción indicada assertThrows(NumberFormatException.class, () -> Integer.parseInt("NaN"))

Ejemplo:

@Test
void testAssertions() {
    assertEquals(4, 2 + 2, "La suma de dos números debe ser correcta");
    assertTrue(3 > 2, "3 es mayor que 2 — eso es cierto");
    assertThrows(ArithmeticException.class, () -> {
        int result = 10 / 0;
    }, "Se esperaba ArithmeticException al dividir por 0");
}

Ciclo de vida de los tests en JUnit 5

Los tests en JUnit pasan por un ciclo de vida determinado:

  1. Se crea el objeto de la clase de test.
  2. Se invoca el método anotado con @BeforeEach.
  3. Se ejecuta el test.
  4. Se invoca el método anotado con @AfterEach.
  5. Se repite para cada test.

Los métodos con @BeforeAll y @AfterAll se ejecutan una vez por toda la clase.


Práctica: Escribir Unit-tests para métodos sencillos

Supongamos que tenemos la clase Calculator:


class Calculator {

    int add(int a, int b) {
        return a + b;
    }

    int subtract(int a, int b) {
        return a - b;
    }

    int multiply(int a, int b) {
        return a * b;
    }

    int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("No se permite dividir por cero");
        }
        return a / b;
    }
}

Y los tests para ella:


import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    void testAddition() {
        assertEquals(5, calculator.add(2, 3), "2 + 3 debe ser igual a 5");
    }

    @Test
    void testSubtraction() {
        assertEquals(1, calculator.subtract(3, 2), "3 - 2 debe ser igual a 1");
    }

    @Test
    void testMultiplication() {
        assertEquals(6, calculator.multiply(2, 3), "2 * 3 debe ser igual a 6");
    }

    @Test
    void testDivision() {
        assertEquals(2, calculator.divide(6, 3), "6 / 3 debe ser igual a 2");
    }

    @Test
    void testDivisionByZero() {
        Exception exception = assertThrows(IllegalArgumentException.class, () -> calculator.divide(5, 0));
        assertEquals("No se permite dividir por cero", exception.getMessage());
    }
}

Estos tests comprueban las operaciones aritméticas básicas y manejan la excepción al dividir por cero.


¿Qué suele dejar a la gente más confundida?

  1. ¿Por qué no se ejecutan los tests? Quizá tu método en la clase de tests no está anotado con @Test.
  2. ¿Por qué falla un test? Lee el mensaje de error con atención. Lo más probable es que las expectativas de assertEquals no coincidan con el resultado real.
  3. ¿Cómo escribir tests para métodos privados? Muchas veces los métodos privados se prueban de forma indirecta a través de los públicos.

JUnit 5 es una herramienta potente, y cuanto más practiques con ella, más fácil te resultará escribir tests de calidad. ¡Vamos, rompe tus bugs al estilo de los superhéroes!

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION