W3docs

Anotações JUnit em Java

Anotações essenciais do JUnit 5 — @Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll, @Disabled.

O JUnit 5 é o framework de testes padrão de facto para Java, e quase tudo que você instrui é feito por meio de anotações. Você não escreve um método main nem chama métodos manualmente; você decora métodos comuns com anotações como @Test, @BeforeEach e @AfterAll, e o engine do JUnit os descobre por reflexão e os executa na ordem correta. Este capítulo aborda as anotações essenciais de ciclo de vida — o que cada uma significa, quando ela é acionada e como elas se combinam para oferecer a cada teste um fixture limpo e isolado.

Se você é novo no framework, comece com a introdução ao JUnit; para os auxiliares de asserção que esses testes utilizam, consulte asserções JUnit. As anotações em si são um recurso geral do Java abordado em anotações Java.

As anotações residem em org.junit.jupiter.api

A API do JUnit 5 é o módulo Jupiter. As anotações que você usa no dia a dia vêm de um único pacote:

AnotaçãoAplica-se aExecuta
@Testum métodouma vez por método de teste
@BeforeEachum métodoantes de cada @Test
@AfterEachum métodoapós cada @Test
@BeforeAllum método staticuma vez, antes de qualquer teste na classe
@AfterAllum método staticuma vez, após todos os testes na classe
@Disabledum método ou classenunca (é ignorado e reportado)
@DisplayNameum método ou classedefine um nome legível nos relatórios

Um método marcado com @Test não precisa do modificador public no JUnit 5 (acesso de pacote é suficiente) e deve retornar void.

@Test: a unidade de trabalho

Um método de teste verifica algo com os auxiliares estáticos em org.junit.jupiter.api.Assertions. Se uma asserção falhar, ela lança uma exceção, e o engine registra aquele teste como reprovado sem interromper os outros.

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 é executado em uma instância nova da classe de teste — o JUnit constrói um novo objeto por teste por padrão, portanto, campos definidos em um teste não podem vazar para outro.

@BeforeEach e @AfterEach: fixtures por teste

A configuração que cada teste precisa vai em um método @BeforeEach; a limpeza vai em @AfterEach. Eles envolvem cada @Test, fornecendo a cada teste um ponto 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 é executado mesmo quando o teste falha, o que o torna o lugar certo para liberar recursos abertos em @BeforeEach.

@BeforeAll e @AfterAll: uma vez por classe

Quando a configuração é cara e compartilhável — um contêiner de banco de dados, um servidor embutido iniciado — use @BeforeAll para fazê-lo uma vez e @AfterAll para encerrá-lo uma vez. Como eles são executados antes de qualquer instância existir, devem 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"));
    }
}

A ordem completa do ciclo de vida para uma classe com dois testes é: @BeforeAll → (@BeforeEach@Test@AfterEach) → (@BeforeEach@Test@AfterEach) → @AfterAll. O capítulo sobre ciclo de vida do JUnit detalha essa ordem, incluindo como ela interage com a criação de instâncias.

@Disabled: ignorar sem excluir

@Disabled desativa um teste (ou uma classe inteira). O engine o reporta como ignorado em vez de aprovado ou reprovado, mantendo-o visível. Sempre forneça um motivo.

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

Um exemplo prático: um mini engine de testes

Não há um jar do JUnit neste executor, então o programa abaixo constrói um minúsculo engine próprio com exatamente a mesma estrutura do JUnit. Ele declara anotações de marcação (@BeforeAll, @BeforeEach, @Test, @AfterEach, @AfterAll, @Disabled), define uma pequena classe de teste anotada e, em seguida, usa reflexão — precisamente o que o engine do JUnit faz internamente — para descobrir e executar os métodos na ordem do ciclo de vida e imprimir um resumo de aprovação/reprovação/ignorado.

java— editable, runs on the server

O que observar na execução:

  • @BeforeAll foi impresso exatamente uma vez no topo e @AfterAll exatamente uma vez no final — a configuração e o encerramento em nível de classe envolvem toda a execução, razão pela qual o JUnit exige que sejam static.
  • Cada @Test executado é precedido por uma linha @BeforeEach e seguido por uma linha @AfterEach, portanto, cada teste foi executado com um fixture recém-preparado e realizou a limpeza após si mesmo — o enquadramento por teste que mantém os testes independentes.
  • O método flaky carregava @Disabled, então imprimiu (skipped via @Disabled) e seu corpo nunca foi executado; a asserção que falharia dentro dele nunca foi alcançada, que é exatamente o ponto de desativar em vez de excluir.
  • O loop de descoberta apenas atua em métodos onde isAnnotationPresent(Test.class) é verdadeiro — anotações são apenas metadados, e é o engine que as lê via reflexão que as transforma em comportamento, exatamente como o JUnit real funciona.
  • A linha final reporta 2 passed, 0 failed, 1 skipped: dois testes reais foram aprovados, nenhum falhou e o desativado foi contado como ignorado em vez de silenciosamente suprimido — a mesma contabilidade de aprovação/reprovação/ignorado que um relatório do JUnit fornece.

Prática

Prática
No JUnit 5, por que um método anotado com @BeforeAll deve ser declarado static?
No JUnit 5, por que um método anotado com @BeforeAll deve ser declarado static?
Was this page helpful?