Asserções JUnit em Java
Verifique comportamentos no JUnit 5 com assertEquals, assertTrue, assertThrows, assertAll e muito mais.
Uma asserção é o momento em que um teste para de descrever e começa a verificar — ela declara o que o código deve produzir e reprova o teste se a realidade não corresponder. O JUnit 5 (a API Jupiter) agrupa cada asserção como métodos static em uma única classe, org.junit.jupiter.api.Assertions. Aprenda esse conjunto de métodos e você conseguirá expressar praticamente qualquer expectativa: igualdade, verdade, nulidade, identidade de objetos, exceções lançadas, limites de tempo e verificações agrupadas. Este capítulo percorre os métodos que você usará no dia a dia.
Se você é novo no framework, leia primeiro a introdução ao JUnit e depois as anotações do JUnit para entender a origem dos métodos @Test. As asserções ficam dentro desses métodos.
O modelo mental: uma asserção com falha reprova o teste
Um método de teste JUnit é executado de cima para baixo. Cada asserção satisfeita é silenciosa; a primeira que não for satisfeita lança um AssertionFailedError, que o JUnit captura e registra como falha — o método para nesse ponto. Portanto, as asserções são os pontos de saída do teste. A ordem convencional dos argumentos é esperado primeiro, real depois, e todo método aceita uma mensagem final opcional usada somente quando a verificação falha:
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class CalculatorTest {
@Test
void addsTwoNumbers() {
int result = 2 + 3;
assertEquals(5, result, "2 + 3 should equal 5");
}
}Você importa os métodos de forma estática (import static ... Assertions.*) para que o corpo do teste seja lido como inglês simples — assertEquals(...), não Assertions.assertEquals(...).
Igualdade, verdade e nulidade
Esses quatro cobrem a grande maioria das asserções reais:
| Método | Passa quando |
|---|---|
assertEquals(expected, actual) | expected.equals(actual) é verdadeiro |
assertNotEquals(unexpected, actual) | os dois não são iguais |
assertTrue(condition) / assertFalse(condition) | o booleano é true / false |
assertNull(obj) / assertNotNull(obj) | a referência é / não é null |
assertSame(expected, actual) | ambos referenciam o mesmo objeto (==) |
assertArrayEquals(expected, actual) | arrays são iguais elemento a elemento |
assertEquals("HELLO", "hello".toUpperCase());
assertTrue(List.of(1, 2, 3).contains(2), "list should contain 2");
assertNull(map.get("missing"));
assertNotSame(new String("a"), new String("a")); // distinct objects
assertArrayEquals(new int[]{1, 2, 3}, computeRange(3));assertEquals usa .equals(), portanto dois objetos String distintos com os mesmos caracteres são aprovados; assertSame usa ==, portanto eles falham. Use assertSame apenas quando a identidade do objeto é o que você pretende testar.
Testando exceções com assertThrows
Um teste às vezes verifica que o código falha — que uma entrada inválida lança uma exceção. assertThrows recebe o tipo de exceção e uma lambda; passa somente se a execução da lambda lançar aquele tipo (ou um subtipo), e retorna a exceção capturada para que você possa inspecionar a sua mensagem:
@Test
void rejectsNullName() {
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> greet(null));
assertEquals("name must not be null", ex.getMessage());
}Seu oposto é assertDoesNotThrow, que falha se a lambda lançar qualquer coisa — útil para assegurar que um caminho anteriormente problemático agora é executado sem erros. (Para as regras sobre o que seu código lança, veja exceções em Java.)
Agrupando com assertAll
Por padrão, a primeira asserção com falha encerra o método, ocultando problemas posteriores. assertAll executa todas as asserções contidas mesmo quando algumas falham, e depois relata todas as falhas juntas — ideal para verificar várias propriedades de um objeto:
@Test
void buildsCompleteUser() {
User u = User.of("[email protected]");
assertAll("user",
() -> assertEquals("[email protected]", u.email()),
() -> assertTrue(u.isActive()),
() -> assertNotNull(u.createdAt()));
}Se tanto o e-mail quanto o sinalizador de ativo estiverem errados, uma única execução informa os dois — em vez de corrigir um, executar novamente e descobrir o próximo.
Um exemplo prático: uma execução de teste autovalidante sem framework
O executor de código não tem JUnit no seu classpath, então este programa implementa a mesma ideia em Java puro: pequenos auxiliares assertEquals, assertTrue, assertThrows e assertAll que se comportam como os do Jupiter — silenciosos no sucesso, explícitos na falha — executando alguns métodos sob teste e imprimindo um resumo no estilo de runner ao final. A API que você escreveria de verdade está nos blocos estáticos acima; isso mostra o que esses métodos fazem.
O que observar na execução:
- As verificações aprovadas não produzem nenhuma linha de falha — apenas
add(2,3) verified == 5etag conditions verifiedsão impressos, refletindo a regra do JUnit de que uma asserção satisfeita é silenciosa e somente as falhas falam. assertThrowsimprimiucaught expected IllegalArgumentException: name must not be null, mostrando o padrão: a lambda deve lançar, o tipo deve corresponder, e a mensagem da exceção capturada é sua para verificar em seguida.assertAll ran 3 checks, 0 failedconfirma o comportamento de agrupamento — todas as três lambdas foram executadas e contabilizadas juntas, que é exatamente o motivo pelo qualassertAllexpõe todos os problemas em uma única passagem em vez de parar no primeiro.- O
SUMMARY -> passed: 7, failed: 0final conta sete asserções individuais em todo o programa (uma de igualdade, duas booleanas, uma de exceção e três dentro deassertAll), a mesma contagem que um runner real reporta — cada chamadaassertXé uma verificação. - Nada aqui importou um framework de testes, mas a estrutura é idêntica à do Jupiter: auxiliares que são silenciosos no sucesso e explícitos na falha. Substituir esses por
org.junit.jupiter.api.Assertions.*mudaria as importações, não a forma como você raciocina sobre cada verificação.
A ordem dos argumentos confunde quase todo mundo no início: é assertEquals(expected, actual), nunca o inverso. Inverta-os e o teste ainda funciona, mas uma mensagem de falha fica ao contrário — ela afirma que o seu valor correto está errado e o com bug está certo. Mantenha o valor literal ou conhecido-correto primeiro.
O que fazer a seguir
As asserções são apenas uma parte de um método de teste. Para usá-las de forma eficaz:
- Agrupe configuração e limpeza ao redor delas com os callbacks do ciclo de vida do JUnit (
@BeforeEach,@AfterEach). - Execute as mesmas asserções para muitas entradas sem copiar e colar usando testes parametrizados.
- Revise a referência de anotações para
@Test,@DisplayNamee@Disabled.