Testes de Integração de Aplicações Java com Docker
O desenvolvimento Java moderno é impensável sem testes de qualidade. No entanto, os testes unitários muitas vezes não conseguem identificar problemas que surgem na interação de componentes com bancos de dados reais, filas de mensagens ou APIs externas. É aqui que os testes de integração entram em cena, e o Docker torna esse processo simples, reproduzível e isolado. Neste artigo, vamos explorar como usar efetivamente o Docker para testes de integração de aplicações Java, utilizando a biblioteca Testcontainers e o Docker Compose.
Por que o Docker muda as regras do jogo nos testes de integração?
A abordagem tradicional para testes de integração frequentemente exige a instalação e configuração de todas as dependências (bancos de dados, brokers de mensagens) na máquina local do desenvolvedor ou no servidor de CI. Isso leva a uma série de problemas:
- Instabilidade do ambiente: Versões diferentes de SGBDs, conflitos de porta, diferenças entre o ambiente de desenvolvimento e produção.
- Complexidade na configuração de CI/CD: Necessidade de instalar e configurar manualmente os serviços no pipeline.
- Poluição de dados: Dados de teste podem permanecer no banco de dados local, afetando execuções subsequentes.
- Paralelização: A execução simultânea de testes na mesma máquina pode causar conflitos.
O Docker resolve esses problemas fornecendo contêineres leves, isolados e efêmeros. Cada teste (ou conjunto de testes) pode iniciar sua própria instância do PostgreSQL, Redis ou Kafka e, após a conclusão do teste, destruí-la. Isso garante a limpeza e a repetibilidade dos resultados.
Configuração do Projeto: Testcontainers vs Docker Compose
Existem duas abordagens principais para integrar o Docker nos testes Java. Vamos analisar ambas.
1. Testcontainers: biblioteca para gerenciar contêineres a partir do código
Testcontainers é uma biblioteca Java que permite gerenciar o ciclo de vida de contêineres Docker diretamente dos seus testes. É o padrão de facto para testes de integração no ecossistema Spring Boot e além.
Vantagens:
- Gerenciamento programático: os contêineres são iniciados e parados automaticamente.
- Suporte para serviços populares "prontos para uso" (GenericContainer, PostgreSQLContainer, KafkaContainer, etc.).
- Seleção automática de portas livres (evita conflitos).
- Ideal para testes de integração modulares.
Exemplo: Testando um REST controller com PostgreSQL
Adicione a dependência ao seu pom.xml (Maven):
<dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.19.3</version> <scope>test</scope></dependency><dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>1.19.3</version> <scope>test</scope></dependency>Agora vamos escrever um teste para uma aplicação Spring Boot que funciona com PostgreSQL:
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.boot.test.web.client.TestRestTemplate;import org.springframework.http.ResponseEntity;import org.testcontainers.containers.PostgreSQLContainer;import org.testcontainers.junit.jupiter.Container;import org.testcontainers.junit.jupiter.Testcontainers;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnviron