Pruebas unitarias en Java con JUnit 6

Las pruebas unitarias son programas que comprueban que tu código hace lo que debe, y que avisan en cuanto algo se rompe. En Java el estándar es JUnit, que llegó a la versión 6 en 2025. Aquí probamos una función que calcula el IVA, con pruebas normales, parametrizadas y de excepciones, y las ejecutamos desde la terminal, sin Maven ni Gradle.

El código que vamos a probar

package mx.ejemplo;

public class Iva {
    public static final double TASA = 0.16;

    public static long totalEnCentavos(long subtotalCentavos) {
        if (subtotalCentavos < 0) throw new IllegalArgumentException("subtotal negativo");
        return Math.round(subtotalCentavos * (1 + TASA));
    }
}

Trabajar con centavos en un long evita los errores de redondeo de double con el dinero (lo explicamos en dinero con BigDecimal).

Las pruebas

package mx.ejemplo;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

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

class IvaTest {
    @Test
    @DisplayName("100 pesos con IVA son 116")
    void cienPesos() {
        assertEquals(11_600, Iva.totalEnCentavos(10_000));
    }

    @ParameterizedTest(name = "{0} centavos -> {1}")
    @CsvSource({"0, 0", "1, 1", "99, 115", "125000, 145000"})
    void variosSubtotales(long subtotal, long esperado) {
        assertEquals(esperado, Iva.totalEnCentavos(subtotal));
    }

    @Test
    void rechazaNegativos() {
        var e = assertThrows(IllegalArgumentException.class, () -> Iva.totalEnCentavos(-1));
        assertEquals("subtotal negativo", e.getMessage());
    }
}
  • @Test marca cada método de prueba. No tiene que ser público ni devolver nada.
  • assertEquals(esperado, real) falla si no coinciden. El orden importa para que el mensaje de error se entienda.
  • @ParameterizedTest con @CsvSource ejecuta la misma prueba con varios datos: cuatro casos en una sola función, incluido el redondeo (99 centavos con IVA son 114.84, que se redondean a 115).
  • assertThrows comprueba que se lanza la excepción esperada, y devuelve la excepción para revisar su mensaje.

Compilar y ejecutar desde la terminal

cd junit
JUNIT=../lib/junit-platform-console-standalone-6.1.3.jar
javac -d out -cp $JUNIT src/mx/ejemplo/Iva.java test/mx/ejemplo/IvaTest.java
java -jar $JUNIT execute --class-path out --scan-class-path --disable-banner --disable-ansi-colors --details=tree
salida╷
├─ JUnit Platform Suite ✔
├─ JUnit Jupiter ✔
│  └─ IvaTest ✔
│     ├─ 100 pesos con IVA son 116 ✔
│     ├─ rechazaNegativos() ✔
│     └─ variosSubtotales(long, long) ✔
│        ├─ "0" centavos -> "0" ✔
│        ├─ "1" centavos -> "1" ✔
│        ├─ "99" centavos -> "115" ✔
│        └─ "125000" centavos -> "145000" ✔
└─ JUnit Vintage ✔

Test run finished after 129 ms

El archivo junit-platform-console-standalone trae todo JUnit en un solo .jar: se descarga de Maven Central. En un proyecto real las pruebas las ejecuta Maven (mvn test) o Gradle (gradle test), que además bajan JUnit solos; las pruebas se escriben exactamente igual.

Cuando una prueba falla

Si alguien cambia la tasa a 0.15 por error, la primera prueba falla con un mensaje que dice exactamente qué esperaba y qué obtuvo, por ejemplo expected: <11600> but was: <11500>, y el resumen termina en rojo. Para eso sirven: el error aparece en tu computadora, no en la factura de un cliente.

Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.