W3docs

Anotaciones JUnit en Java

Anotaciones principales de JUnit 5: @Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll y @Disabled.

JUnit 5 es el framework de pruebas estándar de facto para Java, y casi todo lo que le indicas ocurre a través de anotaciones. No escribes un método main ni llamas a métodos tú mismo; decorás métodos ordinarios con anotaciones como @Test, @BeforeEach y @AfterAll, y el motor de JUnit los descubre por reflexión y los ejecuta en el orden correcto. Este capítulo cubre las anotaciones principales del ciclo de vida — qué significa cada una, cuándo se dispara y cómo se combinan para dar a cada prueba un entorno limpio y aislado.

Si eres nuevo en el framework, comienza con la introducción a JUnit; para los ayudantes de aserciones que invocan estas pruebas, consulta aserciones de JUnit. Las anotaciones en sí son una característica general de Java tratada en anotaciones de Java.

Las anotaciones viven en org.junit.jupiter.api

La API de JUnit 5 es el módulo Jupiter. Las anotaciones que usas a diario provienen de un solo paquete:

AnotaciónSe aplica aSe ejecuta
@Testun métodouna vez por método de prueba
@BeforeEachun métodoantes de cada @Test
@AfterEachun métododespués de cada @Test
@BeforeAllun método staticuna vez, antes de cualquier prueba en la clase
@AfterAllun método staticuna vez, después de todas las pruebas en la clase
@Disabledun método o clasenunca (se omite y se notifica)
@DisplayNameun método o claseestablece un nombre legible en los informes

Un método marcado con @Test no necesita el modificador public en JUnit 5 (el acceso de paquete es válido) y debe retornar void.

@Test: la unidad de trabajo

Un método de prueba afirma algo usando los ayudantes estáticos de org.junit.jupiter.api.Assertions. Si una aserción falla, lanza una excepción y el motor registra esa prueba como fallida sin detener las demás.

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

class CalculatorTest {

    @Test
    void addsTwoNumbers() {
        Calculator calc = new Calculator();
        assertEquals(5, calc.add(2, 3));
    }

    @Test
    void throwsOnDivideByZero() {
        Calculator calc = new Calculator();
        assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
    }
}

Cada @Test se ejecuta en una instancia nueva de la clase de prueba — JUnit construye un nuevo objeto por prueba de forma predeterminada, por lo que los campos establecidos en una prueba no pueden filtrarse a otra.

@BeforeEach y @AfterEach: entornos por prueba

La configuración que necesita cada prueba va en un método @BeforeEach; la limpieza va en @AfterEach. Encuadran cada @Test, proporcionando a cada prueba un punto de partida idéntico.

import org.junit.jupiter.api.*;

class OrderServiceTest {

    private OrderService service;

    @BeforeEach
    void setUp() {
        service = new OrderService(new InMemoryRepo()); // fresh state per test
    }

    @AfterEach
    void tearDown() {
        service.close(); // runs even if the test threw
    }

    @Test
    void placesOrder() {
        assertTrue(service.place("SKU-1", 2));
    }
}

@AfterEach se ejecuta incluso cuando la prueba falla, lo que lo convierte en el lugar correcto para liberar recursos que abriste en @BeforeEach.

@BeforeAll y @AfterAll: una vez por clase

Cuando la configuración es costosa y se puede compartir — un contenedor de base de datos, un servidor embebido iniciado — usa @BeforeAll para hacerlo una vez y @AfterAll para desmontarlo una vez. Como se ejecutan antes de que exista alguna instancia, deben ser static.

import org.junit.jupiter.api.*;

class RepositoryTest {

    static Database db;

    @BeforeAll
    static void startDatabase() {
        db = Database.start();   // runs once, before everything
    }

    @AfterAll
    static void stopDatabase() {
        db.stop();               // runs once, after everything
    }

    @Test
    void savesRow() {
        assertEquals(1, db.insert("hello"));
    }
}

El orden completo del ciclo de vida para una clase con dos pruebas es: @BeforeAll → (@BeforeEach@Test@AfterEach) → (@BeforeEach@Test@AfterEach) → @AfterAll. El capítulo ciclo de vida de JUnit detalla este orden, incluyendo cómo interactúa con la creación de instancias.

@Disabled: omitir sin eliminar

@Disabled desactiva una prueba (o una clase entera). El motor la reporta como omitida en lugar de aprobada o fallida, por lo que permanece visible. Siempre incluye una razón.

@Test
@Disabled("flaky until the rate-limiter fix lands — see JIRA-1234")
void callsExternalApi() {
    // not executed
}

Un ejemplo completo: un mini motor de pruebas

No hay un jar de JUnit en este ejecutor, así que el programa a continuación construye un pequeño motor propio con exactamente la misma forma que JUnit. Declara anotaciones marcadoras (@BeforeAll, @BeforeEach, @Test, @AfterEach, @AfterAll, @Disabled), define una pequeña clase de prueba anotada y luego usa reflexión — precisamente lo que hace el motor de JUnit internamente — para descubrir y ejecutar los métodos en orden de ciclo de vida e imprimir un resumen de aprobado/fallido/omitido.

java— editable, runs on the server

Lo que se puede observar en la ejecución:

  • @BeforeAll se imprime exactamente una vez al inicio y @AfterAll exactamente una vez al final — la configuración y el desmontaje a nivel de clase encuadran toda la ejecución, razón por la que JUnit requiere que sean static.
  • Cada @Test ejecutado está precedido por una línea @BeforeEach y seguido por una línea @AfterEach, por lo que cada prueba se ejecutó contra un entorno recién preparado y se limpió al terminar — el encuadre por prueba que mantiene las pruebas independientes.
  • El método flaky llevaba @Disabled, por lo que imprimió (skipped via @Disabled) y su cuerpo nunca se ejecutó; la aserción fallida dentro de él nunca se alcanzó, que es el objetivo de deshabilitar en lugar de eliminar.
  • El bucle de descubrimiento solo actúa sobre métodos donde isAnnotationPresent(Test.class) es verdadero — las anotaciones son solo metadatos, y es el motor el que las lee mediante reflexión para convertirlas en comportamiento, exactamente como funciona JUnit real.
  • La línea final reporta 2 passed, 0 failed, 1 skipped: dos pruebas reales pasaron, ninguna falló, y la deshabilitada se contó como omitida en lugar de ignorarse silenciosamente — la misma contabilidad de aprobado/fallido/omitido que te da un informe de JUnit.

Práctica

Práctica
En JUnit 5, ¿por qué debe declararse static un método anotado con @BeforeAll?
En JUnit 5, ¿por qué debe declararse static un método anotado con @BeforeAll?
Was this page helpful?