Testes automatizados para iniciantes: primeiros testes com JUnit 5
Testes automatizados com JUnit são programas que verificam se o seu programa Java faz o que deveria. Em vez de abrir a aplicação e testar manualmente, clicando e conferindo, você escreve testes que rodam em segundos, sempre que o código muda. Eles pegam erros antes de chegarem ao cliente e dão segurança para melhorar o código sem medo de quebrar o que já funcionava. Para quem procura a primeira vaga, saber escrever testes é um diferencial claro.
O que é um teste unitário
Um teste unitário verifica uma pequena parte do código, geralmente um método, de forma isolada. Imagine uma classe que calcula o preço de um serviço:
public class CalculadoraPreco {
public BigDecimal calcular(BigDecimal custo, BigDecimal percentuais) {
if (custo == null || custo.signum() < 0) {
throw new IllegalArgumentException("Custo inválido");
}
BigDecimal divisor = BigDecimal.ONE.subtract(percentuais);
if (divisor.signum() <= 0) {
throw new IllegalArgumentException("Percentuais devem somar menos de 100%");
}
return custo.divide(divisor, 2, RoundingMode.HALF_UP);
}
}
A lógica vem do artigo como calcular o preço de um serviço: preço = custo ÷ (1 − percentuais).
Configurando o JUnit 5
Em projetos Spring Boot, o JUnit 5 já vem com a dependência spring-boot-starter-test. Em um projeto Maven comum, adicione o JUnit Jupiter como dependência de teste. Os testes ficam em src/test/java, espelhando os pacotes do código.
O primeiro teste
import static org.junit.jupiter.api.Assertions.*;
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
class CalculadoraPrecoTest {
private final CalculadoraPreco calculadora = new CalculadoraPreco();
@Test
void deveCalcularPrecoComPercentuais() {
BigDecimal preco = calculadora.calcular(new BigDecimal("360"), new BigDecimal("0.30"));
assertEquals(new BigDecimal("514.29"), preco);
}
@Test
void deveRejeitarCustoNegativo() {
assertThrows(IllegalArgumentException.class,
() -> calculadora.calcular(new BigDecimal("-1"), new BigDecimal("0.10")));
}
@Test
void deveRejeitarPercentuaisDeCemPorCento() {
assertThrows(IllegalArgumentException.class,
() -> calculadora.calcular(new BigDecimal("100"), BigDecimal.ONE));
}
}
Rode com mvn test ou pelo botão da IDE.
A estrutura Arrange, Act, Assert
Todo teste segue três passos:
- Arrange (preparar): monte os dados e os objetos.
- Act (agir): chame o método testado.
- Assert (verificar): confira o resultado.
Bons nomes
O nome do teste deve dizer o comportamento esperado: deveRejeitarCustoNegativo é muito mais útil, quando falha, do que teste2.
Testes parametrizados
Para testar vários casos sem repetir código:
@ParameterizedTest
@CsvSource({
"100, 0.20, 125.00",
"360, 0.30, 514.29",
"0, 0.10, 0.00"
})
void deveCalcularVariosCasos(String custo, String percentuais, String esperado) {
assertEquals(new BigDecimal(esperado),
calculadora.calcular(new BigDecimal(custo), new BigDecimal(percentuais)));
}
(É preciso a dependência junit-jupiter-params, já incluída no starter de testes do Spring Boot.)
Isolando dependências com Mockito
Quando a classe depende de banco de dados, e-mail ou APIs externas, o teste unitário substitui essas dependências por mocks, objetos falsos com comportamento controlado:
@ExtendWith(MockitoExtension.class)
class PedidoServiceTest {
@Mock PedidoRepository repository;
@Mock EmailService email;
@InjectMocks PedidoService service;
@Test
void deveEnviarEmailAoConfirmarPedido() {
Pedido pedido = new Pedido(10L, "ana@exemplo.com");
when(repository.findById(10L)).thenReturn(Optional.of(pedido));
service.confirmar(10L);
verify(email).enviarConfirmacao("ana@exemplo.com", 10L);
}
}
Use mocks com moderação. Mockar tudo deixa os testes frágeis e acoplados à implementação.
Testes de API no Spring Boot
Para testar um controller sem subir o servidor inteiro, use @WebMvcTest com MockMvc:
@WebMvcTest(ClienteController.class)
class ClienteControllerTest {
@Autowired MockMvc mvc;
@MockitoBean ClienteService service;
@Test
void deveRetornar404QuandoClienteNaoExiste() throws Exception {
when(service.buscar(99L)).thenThrow(new ClienteNaoEncontradoException(99L));
mvc.perform(get("/clientes/99"))
.andExpect(status().isNotFound());
}
}
Em versões anteriores ao Spring Boot 3.4, a anotação equivalente é @MockBean. Teste também os códigos de status corretos; veja códigos de status HTTP explicados. Para a base da API, veja sua primeira API com Spring Boot.
O que testar primeiro
- Regras de negócio: cálculos, validações, decisões. São onde os erros custam mais.
- Casos de borda: valores zero, nulos, negativos, listas vazias, limites.
- Bugs corrigidos: ao corrigir um bug, escreva um teste que o reproduz. Ele garante que o bug não volta.
Não persiga 100% de cobertura. Uma cobertura alta com testes que não verificam nada útil é pior que uma cobertura menor com testes significativos.
Testes no fluxo de trabalho
Rode os testes antes de cada commit e configure a integração contínua (por exemplo, GitHub Actions) para rodá-los em cada pull request. Veja Git: branches e pull requests. Ter testes em projetos pessoais no GitHub também chama a atenção de recrutadores; veja portfólio de desenvolvedor júnior.
Sistemas sob medida
A PruPru desenvolve APIs, sistemas web e integrações com as mesmas práticas descritas neste guia. Se a sua empresa precisa de software bem construído, conheça os serviços.
Ver serviços →Perguntas frequentes
Qual a diferença entre teste unitário e teste de integração?
O teste unitário verifica uma parte pequena do código de forma isolada, geralmente com dependências simuladas. O teste de integração verifica várias partes funcionando juntas, como a aplicação conversando com um banco de dados real.
Preciso de 100% de cobertura de testes?
Não. A cobertura é um indicador, não um objetivo. Priorize testes das regras de negócio, dos casos de borda e dos bugs já corrigidos. Testes que não verificam nada útil só aumentam o número.
O que é mock?
É um objeto falso que substitui uma dependência real, como um repositório ou um serviço externo, com comportamento controlado no teste. Ele permite testar uma classe isoladamente.
Devo escrever os testes antes ou depois do código?
As duas abordagens funcionam. Escrever antes, como no TDD, ajuda a pensar no comportamento esperado. Para iniciantes, começar escrevendo testes logo depois do código já traz muitos benefícios.