W3docs

Ciclo de Vida dos Testes JUnit no Java

Ciclo de vida de instâncias de teste e comportamento por método vs. por classe no JUnit 5.

Todo teste JUnit 5 é executado dentro de um ciclo de vida bem definido: uma sequência de hooks de configuração e limpeza que são disparados em torno dos seus métodos @Test em uma ordem garantida. Compreender essa ordem — e a regra de que o JUnit cria uma nova instância da classe de teste para cada método de teste — é o que separa suítes de teste frágeis e dependentes de ordem das limpas e isoladas. Este capítulo percorre as cinco anotações de ciclo de vida e os dois ciclos de vida de instância que o JUnit oferece.

As cinco anotações de ciclo de vida

O JUnit 5 (o pacote org.junit.jupiter.api) define quatro anotações de callback que envolvem seus testes, além do próprio @Test. Para um tour mais completo de cada uma, veja anotações JUnit; se você é novo no framework, comece pela introdução ao JUnit.

AnotaçãoExecutaO método deve ser
@BeforeAllUma vez, antes de qualquer teste na classestatic (no ciclo de vida padrão)
@BeforeEachAntes de cada método @Testinstância
@TestO próprio testeinstância
@AfterEachApós cada método @Testinstância
@AfterAllUma vez, após todos os testes terem sido executadosstatic (no ciclo de vida padrão)

Uma única classe de teste com três testes dispara @BeforeAll uma vez, depois @BeforeEach@Test@AfterEach três vezes, e então @AfterAll uma vez.

import org.junit.jupiter.api.*;

class CalculatorTest {
  @BeforeAll  static void initSuite() { System.out.println("once, up front"); }
  @BeforeEach void setUp()           { System.out.println("before each test"); }

  @Test void add()      { Assertions.assertEquals(4, 2 + 2); }
  @Test void subtract() { Assertions.assertEquals(0, 2 - 2); }

  @AfterEach void tearDown()    { System.out.println("after each test"); }
  @AfterAll  static void close() { System.out.println("once, at the end"); }
}

Uma nova instância por método de teste

A regra mais importante do ciclo de vida: por padrão, o JUnit constrói uma nova instância da classe de teste antes de cada método de teste. Campos que você modifica em um teste não podem vazar para outro, porque o próximo teste é executado em um objeto diferente. É isso que torna os testes independentes da ordem de execução.

class IsolationTest {
  private int counter = 0; // re-initialised for every test

  @Test void first()  { counter++; Assertions.assertEquals(1, counter); }
  @Test void second() { counter++; Assertions.assertEquals(1, counter); } // also 1, not 2
}

Ambos os testes veem counter == 1. Se o JUnit reutilizasse uma única instância, o segundo teste observaria 2 e passaria ou falharia dependendo da ordem — exatamente a fragilidade que este design previne.

PER_METHOD vs. PER_CLASS

Você pode sair do ciclo de vida por método usando @TestInstance(Lifecycle.PER_CLASS). Nesse caso, o JUnit cria uma instância para toda a classe, os campos de instância persistem entre os testes e — como conveniência — @BeforeAll/@AfterAll podem ser não-static.

AspectoPER_METHOD (padrão)PER_CLASS
Instâncias criadasuma por @Testuma por classe
Estado dos campos de instânciareiniciado a cada testecompartilhado entre testes
@BeforeAll/@AfterAlldeve ser staticpode ser método de instância
Melhor paraisolamento máximoconfiguração compartilhada custosa
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.TestInstance.Lifecycle;

@TestInstance(Lifecycle.PER_CLASS)
class SharedFixtureTest {
  @BeforeAll void openConnection() { /* non-static is now legal */ }
  @AfterAll  void closeConnection() { }
}

Use PER_CLASS apenas quando a configuração é genuinamente custosa e segura para compartilhar. O padrão oferece isolamento de graça.

Assertions são como um teste reporta falha

Um ciclo de vida existe para executar assertions. Assertions.assertEquals(expected, actual) lança um AssertionFailedError quando os valores diferem, o que interrompe esse único teste (seu @AfterEach ainda é executado) e o marca como falho — os outros testes continuam. Veja assertions JUnit para o conjunto completo de métodos assert*.

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

@Test void example() {
  assertEquals(42, compute());
  assertTrue(isReady());
  assertThrows(IllegalArgumentException.class, () -> parse("bad"));
}

Um exemplo prático: rastreando o ciclo de vida manualmente

Não há um executor JUnit neste playground de código, portanto o programa abaixo modela o ciclo de vida em código JDK simples: dispara os hooks na ordem do JUnit, contrasta PER_METHOD (uma nova instância por teste) com PER_CLASS (uma instância compartilhada), e termina com um pequeno harness de auto-verificação no espírito de assertEquals.

java— editable, runs on the server

O que observar na execução:

  • O bloco PER_METHOD imprime instance#1, instance#2, instance#3 para os três testes, comprovando a regra padrão do JUnit: uma nova instância de teste é construída para cada método @Test, portanto nenhum teste pode ver o estado mutado de outro teste.
  • Em PER_METHOD, cada linha [TEST] reporta counter=1, nunca 2 ou 3. Cada instância obteve seu próprio campo novo, o que é por isso que os testes permanecem independentes da ordem de execução — o benefício central do ciclo de vida padrão.
  • O bloco PER_CLASS reutiliza instance#1 para todos os três testes, e seu counter sobe 1 → 2 → 3. Com uma única instância compartilhada, o estado dos campos de instância vaza deliberadamente entre os testes — útil para fixtures compartilhadas custosas, perigoso se você se esquecer disso.
  • @BeforeAll e @AfterAll aparecem exatamente uma vez por bloco, envolvendo os pares @BeforeEach/@AfterEach por teste que disparam três vezes — a ordem de aninhamento exata que o JUnit garante em torno de seus testes.
  • O harness final imprime PASS: para todas as três verificações; um check que falha lança um AssertionError com uma mensagem FAIL:, espelhando como Assertions.assertEquals interrompe um único teste com um AssertionFailedError enquanto deixa os outros serem executados.

Capítulos relacionados

Prática

Prática
No JUnit 5 com o ciclo de vida de instância de teste padrão, quantas instâncias de uma classe de teste contendo três métodos @Test são criadas quando a classe é executada?
No JUnit 5 com o ciclo de vida de instância de teste padrão, quantas instâncias de uma classe de teste contendo três métodos @Test são criadas quando a classe é executada?
Was this page helpful?