public class CustomPostgreSQLContainer extends PostgreSQLContainer<CustomPostgreSQLContainer> { private static final String IMAGE_VERSION = "postgres:15-alpine"; public CustomPostgreSQLContainer() { super(IMAGE_VERSION); this.withDatabaseName("testdb") .withUsername("testuser") .withPassword("testpass") .withInitScript("init.sql") .withCommand("postgres -c max_connections=200"); }}
Integração com Spring Boot
@SpringBootTest@Testcontainersclass ApplicationTests { @Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("testdb"); @DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); registry.add("spring.datasource.password", postgres::getPassword); registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); } @Test void contextLoads() { // Test with real database }}
Casos de Uso Comuns
Caso de Uso 1: Teste de Integração com PostgreSQL
Would you like me to continue with the remaining translations?```java
@Testcontainers
@SpringBootTest
class UserRepositoryTest {
@Containerstatic PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("testdb") .withUsername("test") .withPassword("test") .withInitScript("schema.sql");@DynamicPropertySourcestatic void registerProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); registry.add("spring.datasource.password", postgres::getPassword);}@Autowiredprivate UserRepository userRepository;@Testvoid shouldSaveAndFindUser() { User user = new User("john@example.com", "John Doe"); userRepository.save(user); Optional<User> found = userRepository.findByEmail("john@example.com"); assertTrue(found.isPresent()); assertEquals("John Doe", found.get().getName());}
}
```java@Testcontainersclass KafkaIntegrationTest { @Container static KafkaContainer kafka = new KafkaContainer( DockerImageName.parse("confluentinc/cp-kafka:7.5.0") ); @DynamicPropertySource static void kafkaProperties(DynamicPropertyRegistry registry) { registry.add("spring.kafka.bootstrap-servers", kafka::getBootstrapServers); } @Autowired private KafkaTemplate<String, String> kafkaTemplate; @Autowired private MessageListener messageListener; @Test void shouldProcessMessage() throws Exception { String topic = "test-topic"; String message = "Hello Kafka!"; kafkaTemplate.send(topic, message); // Wait for message processing await().atMost(Duration.ofSeconds(10)) .until(() -> messageListener.getReceivedMessages().size() == 1); assertEquals(message, messageListener.getReceivedMessages().get(0)); }}```### Caso de Uso 3: Teste de Microsserviços Multi-Container```java@Testcontainersclass MicroservicesIntegrationTest { static Network network = Network.newNetwork(); @Container static PostgreSQLContainer<?> database = new PostgreSQLContainer<>("postgres:15-alpine") .withNetwork(network) .withNetworkAliases("database") .withDatabaseName("orders"); @Container static GenericContainer<?> redis = new GenericContainer<>("redis:7-alpine") .withNetwork(network) .withNetworkAliases("redis") .withExposedPorts(6379); @Container static GenericContainer<?> orderService = new GenericContainer<>("order-service:latest") .withNetwork(network) .withExposedPorts(8080) .withEnv("DATABASE_URL", "jdbc:postgresql://database:5432/orders") .withEnv("REDIS_HOST", "redis") .dependsOn(database, redis) .waitingFor(Wait.forHttp("/actuator/health").forStatusCode(200)); @Test void shouldCreateOrder() { String baseUrl = "http://" + orderService.getHost() + ":" + orderService.getMappedPort(8080); // Make HTTP request to order service RestTemplate restTemplate = new RestTemplate(); Order order = new Order("item-123", 2); ResponseEntity<Order> response = restTemplate.postForEntity( baseUrl + "/orders", order, Order.class ); assertEquals(HttpStatus.CREATED, response.getStatusCode()); assertNotNull(response.getBody().getId()); }}```### Caso de Uso 4: Teste de Integração com MongoDB```java@Testcontainers@DataMongoTestclass ProductRepositoryTest { @Container static MongoDBContainer mongodb = new MongoDBContainer("mongo:6.0") .withExposedPorts(27017); @DynamicPropertySource static void mongoProperties(DynamicPropertyRegistry registry) { registry.add("spring.data.mongodb.uri", mongodb::getReplicaSetUrl); } @Autowired private ProductRepository productRepository; @Test void shouldFindProductsByCategory() { // Insert test data productRepository.save(new Product("Laptop", "Electronics", 999.99)); productRepository.save(new Product("Mouse", "Electronics", 29.99)); productRepository.save(new Product("Desk", "Furniture", 299.99)); // Query by category List<Product> electronics = productRepository.findByCategory("Electronics"); assertEquals(2, electronics.size()); assertTrue(electronics.stream() .allMatch(p -> p.getCategory().equals("Electronics"))); }}```### Caso de Uso 5: Ambiente de Teste com Docker Compose```java@Testcontainersclass FullStackIntegrationTest { @Container static DockerComposeContainer<?> environment = new DockerComposeContainer<>( new File("src/test/resources/docker-compose-test.yml") ) .withExposedService("api", 8080, Wait.forHttp("/health").forStatusCode(200)) .withExposedService("postgres", 5432, Wait.forListeningPort()) .withExposedService("redis", 6379) .withLocalCompose(true); @Test void shouldConnectToAllServices() { String apiHost = environment.getServiceHost("api", 8080); Integer apiPort = environment.getServicePort("api", 8080); String apiUrl = "http://" + apiHost + ":" + apiPort; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response = restTemplate.getForEntity( apiUrl + "/health", String.class ); assertEquals(HttpStatus.OK, response.getStatusCode()); }}```## Melhores Práticas### Gerenciamento de Containers- **Use containers estáticos para classes de teste**: Compartilhe containers entre todos os métodos de teste para reduzir tempo de inicialização e uso de recursos- **Implemente reutilização de containers**: Habilite`testcontainers.reuse.enable=true`para ciclos de desenvolvimento local de testes mais rápidos- **Limpe recursos**: Use`@AfterAll`ou try-with-resources ao gerenciar containers manualmente fora da integração JUnit- **Use tags de imagem específicas**: Evite tag`latest`; use versões específicas como`postgres:15-alpine`para testes reproduzíveis### Otimização de Desempenho- **Inicialização paralela de containers**: Use`Startables.deepStart()`para iniciar múltiplos containers independentes simultaneamente- **Minimize reinícios de containers**: Use`@Container`em nível de classe em vez de nível de método quando possível- **Escolha imagens leves**: Prefira imagens baseadas em Alpine (por exemplo,`postgres:15-alpine`) para reduzir tempo de download e uso de disco- **Implemente estratégias de espera com sabedoria**: Use estratégias de espera apropriadas para evitar atrasos desnecessários, garantindo a prontidão do container### Estratégia de Teste- **Teste com dependências semelhantes à produção**: Use mecanismos de banco de dados e message brokers reais em vez de versões embutidas- **Isole dados de teste**: Garanta que cada teste crie e limpe seus próprios dados para evitar interdependências- **Use aliases de rede**: Crie redes personalizadas e use aliases significativos para comunicação entre containers- **Implemente verificações de saúde**: Sempre configure estratégias de espera adequadas para garantir que os containers estejam totalmente prontos antes da execução dos testes### Integração CI/CD- **Verifique a disponibilidade do Docker**: Certifique-se de que o ambiente de CI tenha Docker instalado e acessível- **Configure timeouts adequadamente**: Defina timeouts de inicialização realistas considerando o desempenho do ambiente de CI- **Use cache de imagens**: Configure o CI para armazenar imagens Docker para acelerar execuções subsequentes- **Monitore uso de recursos**: Esteja ciente dos limites de memória e CPU em ambientes de CI; ajuste configurações de containers adequadamente### Segurança e Manutenção- **Mantenha TestContainers atualizado**: Atualize regularmente para as versões mais recentes para correções de segurança e novos recursos- **Use imagens oficiais**: Prefira imagens Docker oficiais de editores verificados- **Evite modo privilegiado**: Use`.withPrivilegedMode()`apenas quando absolutamente necessário- **Revise portas expostas**: Exponha apenas portas realmente necessárias para teste## Solução de Problemas| Problema | Solução ||-------|----------|| **Container fails to start: "Cannot connect to Docker daemon"** | Ensure Docker is running: `docker ps`. On Linux, add user to docker group: `sudo usermod -aG docker $USER` || **Tests timeout during container startup** | Increase timeout: `.withStartupTimeout(Duration.ofMinutes(5))` or check Docker resources (CPU/Memory) || **Port binding conflicts: "Address already in use"** | Use dynamic ports: `container.getMappedPort()` instead of fixed ports, or stop conflicting services || **Image pull fails: "manifest unknown"** | Verify image name and tag exist on Docker Hub. Use specific tags instead of `latest` || **Container starts but tests fail to connect** | Check wait strategy is appropriate: add `.waitingFor(Wait.forListeningPort())` or `.waitingFor(Wait.forHealthcheck())` || **Out of memory errors during tests** | Reduce number of parallel containers, increase Docker memory limit in Docker Desktop settings, or use `.withReuse(true)` || **"Ryuk container not found" warnings** | Disable Ryuk if needed: set `testcontainers.ryuk.disabled=true` in properties (not recommended for production) || **Tests work locally but fail in CI** | Certifique-se de que o CI tenha o Docker instalado, verifique as configurações de timeout, confirme a conectividade de rede, revise os limites de recursos do ambiente CI || **Database connection refused** | Wait for database to be ready: use `.waitingFor(Wait.forListeningPort())` and verify JDBC URL with `container.getJdbcUrl()` || **Container logs show errors but tests pass** | Enable log following: `container.followOutput(new Slf4jLogConsumer(log))` to debug container issues || **Slow test execution** | Use container reuse, share containers at class level, start containers in parallel with `Startables.deepStart()` || **"No such file or directory" when mounting volumes** | Use absolute paths or `MountableFile.forClasspathResource()` for classpath resources || **Network communication between containers fails** | Create custom network: `Network.newNetwork()` and attach containers with `.withNetwork(network)` and `.withNetworkAliases()` || **TestContainers properties not being read** | Ensure `testcontainers.properties` is in `src/test/resources` and properly formatted || **Container cleanup not happening** | Check Ryuk container is running: `docker ps | grep ryuk`. Ensure tests complete normally without hanging |## Módulos Disponíveis| Módulo | Artefato Maven | Descrição ||--------|---------------|-------------|| PostgreSQL | `testcontainers-postgresql` | Contêineres de banco de dados PostgreSQL || MySQL | `testcontainers-mysql` | Contêineres de banco de dados MySQL || MongoDB | `testcontainers-mongodb` | Banco de dados de documentos MongoDB || Kafka | `testcontainers-kafka` | Corretor de mensagens Apache Kafka || Redis | `testcontainers-redis` | Armazenamento de dados em memória Redis || Elasticsearch | `testcontainers-elasticsearch` | Motor de busca Elasticsearch || Cassandra | `testcontainers-cassandra` | Banco de dados NoSQL Cassandra || RabbitMQ | `testcontainers-rabbitmq` | Corretor de mensagens RabbitMQ || Selenium | `testcontainers-selenium` | Contêineres de automação de navegador || LocalStack | `testcontainers-localstack` | Emulação de serviços AWS || Nginx
This site uses cookies for analytics and to improve your experience.
See our Privacy Policy for details.