Testes em Java: unit, integration, e2e do A ao Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que testar é a base do código Java de qualidade

Todo desenvolvedor Java já passou pela situação em que, após corrigir um bug, surgem três novos. Para quebrar esse ciclo vicioso, existe o teste. Não é apenas uma marcação em uma lista de verificação, mas uma disciplina profissional que economiza nervos, dinheiro e a reputação do produto.

Neste artigo, vamos analisar os três níveis principais de teste: unit (unitário), integration (integração) e e2e (end-to-end). Vamos examiná-los com exemplos práticos em Java, usando frameworks populares: JUnit 5, Mockito, Spring Boot Test e Selenium. Você aprenderá como construir a pirâmide de testes correta e não sobrecarregar o projeto com testes inúteis.



1. Teste Unitário: Verificando unidades atômicas de código

Testes unitários são o nível mais baixo e mais rápido. Eles verificam o funcionamento de uma única "unidade" (geralmente um método ou classe) isolada de dependências externas (BD, API, sistema de arquivos).



1.1 Ferramentas e frameworks

  • JUnit 5 — o padrão de facto para escrever testes em Java.
  • Mockito — biblioteca para criar mocks e stubs.
  • AssertJ — biblioteca para verificações (asserções) fluidas.


1.2 Exemplo de Teste Unitário com JUnit 5 e Mockito

Vamos imaginar que temos um serviço OrderService, que depende de um repositório PaymentRepository. Queremos testar a lógica do serviço sem chamar o banco de dados real.

// Classe a ser testadapublic class OrderService {    private final PaymentRepository paymentRepository;

public OrderService(PaymentRepository paymentRepository) { this.paymentRepository = paymentRepository; }

public String processOrder(Order order) { if (order.getAmount() <= 0) { throw new IllegalArgumentException("O valor do pedido deve ser positivo"); } boolean success = paymentRepository.pay(order); return success ? "Pagamento bem-sucedido" : "Erro no pagamento"; }}

// Teste Unitárioimport org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import static org.junit.jupiter.api.Assertions.*;import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)class OrderServiceTest {

@Mock private PaymentRepository paymentRepository;

@InjectMocks private OrderService orderService;

@Test void testProcessOrder_Success() { // Arrange Order order = new Order(100.0); when(paymentRepository.pay(order)).thenReturn(true);

// Act String result = orderService.processOrder(order);

// Assert assertEquals("Pagamento bem-sucedido", result); verify(paymentRepository, times(1)).pay(order); }

@Test void testProcessOrder_NegativeAmount() { // Arrange Order order = new Order(-10.0);

// Act & Assert assertThrows(IllegalArgumentException.class, () -> { orderService.processOrder(order); }); }}

Best Practices para Testes Unitários:

  • Um teste — uma verificação (princípio FIRST: Fast, Isolated, Repeatable, Self-validating, Timely).
  • Use nomes claros: shouldReturnSuccess_whenPaymentIsApproved.
  • Não teste métodos private — teste o contrato público.
  • Cubra casos de borda: null, strings vazias, números negativos.


2. Teste de Integração: Verificando a interação entre componentes

Testes de integração verificam como diferentes módulos do sistema

Blogs

Book Recommendations