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
@DisplayNamees 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:
- Se crea el objeto de la clase de test.
- Se invoca el método anotado con @BeforeEach.
- Se ejecuta el test.
- Se invoca el método anotado con @AfterEach.
- 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?
- ¿Por qué no se ejecutan los tests? Quizá tu método en la clase de tests no está anotado con
@Test. - ¿Por qué falla un test? Lee el mensaje de error con atención. Lo más probable es que las expectativas de
assertEqualsno coincidan con el resultado real. - ¿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!
GO TO FULL VERSION