Introduction
Testcontainers Cloud is a SaaS platform that provides cloud-hosted containers for testing, eliminating the need to run Docker containers locally. It enables faster test execution, parallel testing, and access to a wider range of container configurations.
Setup and Configuration
1. Dependencies
<properties> <testcontainers.version>1.19.3</testcontainers.version> <testcontainers.cloud.version>1.0.0</testcontainers.cloud.version> </properties> <dependencies> <!-- Testcontainers Core --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <!-- Testcontainers Cloud --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers-cloud</artifactId> <version>${testcontainers.cloud.version}</version> <scope>test</scope> </dependency> <!-- JUnit 5 Integration --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <!-- Database Modules --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mongodb</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <!-- Kafka --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>kafka</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <!-- Spring Boot Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>3.2.0</version> <scope>test</scope> </dependency> </dependencies> 2. Configuration Files
# testcontainers.properties testcontainers.reuse.enable=true testcontainers.cloud.enabled=true testcontainers.cloud.host=cloud.testcontainers.com testcontainers.cloud.port=443 testcontainers.cloud.tls.enabled=true # Optional: Service-specific timeouts testcontainers.cloud.timeout=300 testcontainers.cloud.read-timeout=60
# application-test.yml testcontainers: cloud: enabled: true host: cloud.testcontainers.com port: 443 tls-enabled: true auth-token: ${TESTCONTAINERS_CLOUD_TOKEN} spring: datasource: url: jdbc:tc:postgresql:15-alpine:///testdb?TC_INITSCRIPT=init.sql jpa: hibernate: ddl-auto: validate show-sql: true logging: level: org.testcontainers: DEBUG com.github.dockerjava: WARN Basic Testcontainers Cloud Setup
3. Environment Configuration
package com.example.testcontainers.config; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.utility.DockerImageName; @TestConfiguration public class TestContainersCloudConfig { @Bean public PostgreSQLContainer<?> postgreSQLContainer() { return new PostgreSQLContainer<>(DockerImageName.parse("postgres:15-alpine")) .withDatabaseName("testdb") .withUsername("test") .withPassword("test") .withReuse(true); } @Bean public TestcontainersCloudProperties cloudProperties() { return TestcontainersCloudProperties.builder() .enabled(true) .host("cloud.testcontainers.com") .port(443) .authToken(System.getenv("TESTCONTAINERS_CLOUD_TOKEN")) .build(); } } public class TestcontainersCloudProperties { private boolean enabled; private String host; private int port; private String authToken; private boolean tlsEnabled = true; // Builder pattern public static Builder builder() { return new Builder(); } public static class Builder { private final TestcontainersCloudProperties properties = new TestcontainersCloudProperties(); public Builder enabled(boolean enabled) { properties.enabled = enabled; return this; } public Builder host(String host) { properties.host = host; return this; } public Builder port(int port) { properties.port = port; return this; } public Builder authToken(String authToken) { properties.authToken = authToken; return this; } public Builder tlsEnabled(boolean tlsEnabled) { properties.tlsEnabled = tlsEnabled; return this; } public TestcontainersCloudProperties build() { return properties; } } // Getters public boolean isEnabled() { return enabled; } public String getHost() { return host; } public int getPort() { return port; } public String getAuthToken() { return authToken; } public boolean isTlsEnabled() { return tlsEnabled; } } 4. Database Testing with Testcontainers Cloud
package com.example.testcontainers.database; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers @SpringBootTest class PostgreSQLIntegrationTest { @Container private static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("testdb") .withUsername("testuser") .withPassword("testpass") .withInitScript("init.sql") .withReuse(true); @Autowired private JdbcTemplate jdbcTemplate; @Test void testDatabaseConnection() { Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class); assertThat(result).isEqualTo(1); } @Test void testDatabaseOperations() { // Create table and insert data jdbcTemplate.execute(""" CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(100), email VARCHAR(100) ) """); jdbcTemplate.update("INSERT INTO users (name, email) VALUES (?, ?)", "John Doe", "[email protected]"); Integer count = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM users", Integer.class); assertThat(count).isEqualTo(1); } } Advanced Test Scenarios
5. Multi-Container Testing
package com.example.testcontainers.multi; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.containers.Network; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers @SpringBootTest class MultiContainerIntegrationTest { private static final Network network = Network.newNetwork(); @Container private static final KafkaContainer kafka = new KafkaContainer( DockerImageName.parse("confluentinc/cp-kafka:7.4.0")) .withNetwork(network) .withNetworkAliases("kafka"); @Container private static final GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:7-alpine")) .withExposedPorts(6379) .withNetwork(network) .withNetworkAliases("redis") .withCommand("redis-server", "--appendonly", "yes"); @Container private static final GenericContainer<?> elasticsearch = new GenericContainer<>(DockerImageName.parse("elasticsearch:8.11.0")) .withExposedPorts(9200) .withNetwork(network) .withNetworkAliases("elasticsearch") .withEnv("discovery.type", "single-node") .withEnv("xpack.security.enabled", "false"); @Test void testAllContainersAreRunning() { assertThat(kafka.isRunning()).isTrue(); assertThat(redis.isRunning()).isTrue(); assertThat(elasticsearch.isRunning()).isTrue(); System.out.println("Kafka: " + kafka.getBootstrapServers()); System.out.println("Redis: " + redis.getHost() + ":" + redis.getFirstMappedPort()); System.out.println("Elasticsearch: " + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort()); } } 6. Spring Boot Application Testing
package com.example.testcontainers.springboot; 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.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class SpringBootApplicationTest { @Container private static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("testdb") .withUsername("test") .withPassword("test"); @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"); } @Autowired private TestRestTemplate restTemplate; @Test void testApplicationStarts() { ResponseEntity<String> response = restTemplate.getForEntity("/actuator/health", String.class); assertThat(response.getStatusCode().is2xxSuccessful()).isTrue(); } @Test void testDatabaseIntegration() { // Test your application's database integration ResponseEntity<String> response = restTemplate.getForEntity("/api/users", String.class); assertThat(response.getStatusCode().is2xxSuccessful()).isTrue(); } } Testcontainers Cloud Specific Features
7. Cloud Configuration Manager
package com.example.testcontainers.cloud; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.testcontainers.cloud.TestcontainersCloudClient; import java.util.Optional; @Component public class TestcontainersCloudManager { private static final Logger log = LoggerFactory.getLogger(TestcontainersCloudManager.class); private final TestcontainersCloudClient cloudClient; public TestcontainersCloudManager() { this.cloudClient = TestcontainersCloudClient.getInstance(); } public void configureCloudEnvironment() { // Check if running in Testcontainers Cloud if (cloudClient.isCloudEnvironment()) { log.info("Running in Testcontainers Cloud environment"); // Configure cloud-specific settings configureCloudTimeouts(); configureCloudNetworking(); enableCloudFeatures(); } else { log.info("Running in local Testcontainers environment"); } } private void configureCloudTimeouts() { // Increase timeouts for cloud environment System.setProperty("testcontainers.cloud.timeout", "300"); System.setProperty("testcontainers.cloud.read-timeout", "60"); } private void configureCloudNetworking() { // Configure cloud networking if needed System.setProperty("testcontainers.cloud.network-mode", "bridge"); } private void enableCloudFeatures() { // Enable cloud-specific features System.setProperty("testcontainers.cloud.parallelism", "10"); System.setProperty("testcontainers.cloud.cache.enabled", "true"); } public Optional<String> getCloudEndpoint() { return cloudClient.getEndpoint(); } public boolean isCloudHealthy() { try { return cloudClient.isHealthy(); } catch (Exception e) { log.warn("Failed to check cloud health", e); return false; } } } 8. Parallel Test Execution
package com.example.testcontainers.parallel; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers @Execution(ExecutionMode.CONCURRENT) class ParallelDatabaseTest { @Container private static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("testdb") .withUsername("test") .withPassword("test") .withReuse(true); @Test void testParallelExecution1() throws Exception { testDatabaseOperation("test_1"); } @Test void testParallelExecution2() throws Exception { testDatabaseOperation("test_2"); } @Test void testParallelExecution3() throws Exception { testDatabaseOperation("test_3"); } @Test void testParallelExecution4() throws Exception { testDatabaseOperation("test_4"); } private void testDatabaseOperation(String testName) throws Exception { String url = postgres.getJdbcUrl(); try (Connection conn = DriverManager.getConnection(url, "test", "test"); Statement stmt = conn.createStatement()) { // Create test table stmt.execute("CREATE TABLE IF NOT EXISTS parallel_test (id SERIAL, name VARCHAR(100))"); // Insert test data stmt.execute("INSERT INTO parallel_test (name) VALUES ('" + testName + "')"); // Verify insertion ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM parallel_test WHERE name = '" + testName + "'"); rs.next(); int count = rs.getInt(1); assertThat(count).isEqualTo(1); System.out.println("Test " + testName + " completed successfully"); } } } Database Migration Testing
9. Flyway/Liquibase Migration Testing
package com.example.testcontainers.migration; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class DatabaseMigrationTest { @Container private static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("migration_test") .withUsername("flyway") .withPassword("flyway"); private Flyway flyway; @BeforeEach void setUp() { flyway = Flyway.configure() .dataSource(postgres.getJdbcUrl(), "flyway", "flyway") .locations("classpath:db/migration") .load(); } @Test void testDatabaseMigrations() { // Run all migrations flyway.migrate(); // Verify migrations were applied try (Connection conn = flyway.getConfiguration().getDataSource().getConnection(); ResultSet rs = conn.getMetaData().getTables(null, null, "flyway_schema_history", null)) { assertThat(rs.next()).isTrue(); // Verify specific tables were created ResultSet tables = conn.getMetaData().getTables(null, null, "users", null); assertThat(tables.next()).isTrue(); tables = conn.getMetaData().getTables(null, null, "orders", null); assertThat(tables.next()).isTrue(); } catch (Exception e) { throw new RuntimeException("Migration verification failed", e); } } @Test void testMigrationRollback() { // Run migrations flyway.migrate(); // Clean (rollback) - this will drop all objects flyway.clean(); // Verify database is empty try (Connection conn = flyway.getConfiguration().getDataSource().getConnection(); ResultSet rs = conn.getMetaData().getTables(null, null, null, new String[]{"TABLE"})) { int tableCount = 0; while (rs.next()) { String tableName = rs.getString("TABLE_NAME"); if (!"flyway_schema_history".equals(tableName)) { tableCount++; } } assertThat(tableCount).isEqualTo(0); } catch (Exception e) { throw new RuntimeException("Clean verification failed", e); } } } Kafka Testing with Testcontainers Cloud
10. Kafka Integration Testing
package com.example.testcontainers.kafka; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; import org.junit.jupiter.api.Test; import org.testcontainers.containers.KafkaContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import java.time.Duration; import java.util.Collections; import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers class KafkaIntegrationTest { @Container private static final KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")); @Test void testKafkaProducerConsumer() throws InterruptedException { String topic = "test-topic"; String message = "Hello, Kafka!"; // Create producer Properties producerProps = new Properties(); producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers()); producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); KafkaProducer<String, String> producer = new KafkaProducer<>(producerProps); // Create consumer Properties consumerProps = new Properties(); consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers()); consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "test-group"); consumerProps.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(consumerProps); consumer.subscribe(Collections.singletonList(topic)); // Send message producer.send(new ProducerRecord<>(topic, "key", message)); producer.flush(); // Receive message ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(10)); assertThat(records).isNotEmpty(); assertThat(records.iterator().next().value()).isEqualTo(message); producer.close(); consumer.close(); } @Test void testKafkaWithSchemaRegistry() { // This would require a multi-container setup with Schema Registry // Testcontainers Cloud makes this easier by handling the complexity System.out.println("Kafka Bootstrap Servers: " + kafka.getBootstrapServers()); assertThat(kafka.isRunning()).isTrue(); } } Performance Testing
11. Performance Test Base Class
package com.example.testcontainers.performance; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; @Testcontainers @TestInstance(TestInstance.Lifecycle.PER_CLASS) class DatabasePerformanceTest { @Container private static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("perf_test") .withUsername("perf") .withPassword("perf"); private String jdbcUrl; @BeforeAll void setUp() throws Exception { jdbcUrl = postgres.getJdbcUrl(); initializeTestData(); } @Test void testConcurrentDatabaseOperations() throws InterruptedException { int threadCount = 10; int operationsPerThread = 100; ExecutorService executor = Executors.newFixedThreadPool(threadCount); AtomicInteger successCount = new AtomicInteger(0); for (int i = 0; i < threadCount; i++) { final int threadId = i; executor.submit(() -> { try (Connection conn = DriverManager.getConnection(jdbcUrl, "perf", "perf")) { for (int j = 0; j < operationsPerThread; j++) { performDatabaseOperation(conn, threadId, j); successCount.incrementAndGet(); } } catch (Exception e) { System.err.println("Thread " + threadId + " failed: " + e.getMessage()); } }); } executor.shutdown(); boolean terminated = executor.awaitTermination(30, TimeUnit.SECONDS); assertThat(terminated).isTrue(); assertThat(successCount.get()).isEqualTo(threadCount * operationsPerThread); System.out.println("Completed " + successCount.get() + " operations across " + threadCount + " threads"); } private void initializeTestData() throws Exception { try (Connection conn = DriverManager.getConnection(jdbcUrl, "perf", "perf"); PreparedStatement stmt = conn.prepareStatement( "CREATE TABLE IF NOT EXISTS performance_test (id SERIAL, thread_id INT, operation_id INT, data TEXT)")) { stmt.execute(); } } private void performDatabaseOperation(Connection conn, int threadId, int operationId) throws Exception { String sql = "INSERT INTO performance_test (thread_id, operation_id, data) VALUES (?, ?, ?)"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setInt(1, threadId); stmt.setInt(2, operationId); stmt.setString(3, "Data from thread " + threadId + ", operation " + operationId); stmt.executeUpdate(); } } } CI/CD Integration
12. GitHub Actions Workflow
# .github/workflows/testcontainers-cloud.yml name: Test with Testcontainers Cloud on: push: branches: [ main, develop ] pull_request: branches: [ main ] env: TESTCONTAINERS_CLOUD_TOKEN: ${{ secrets.TESTCONTAINERS_CLOUD_TOKEN }} jobs: test: runs-on: ubuntu-latest services: # Local services if needed, but Testcontainers Cloud will handle containers steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Java uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: 'maven' - name: Configure Testcontainers Cloud run: | echo "TESTCONTAINERS_CLOUD_TOKEN=$TESTCONTAINERS_CLOUD_TOKEN" >> $GITHUB_ENV # Configure cloud settings echo "testcontainers.cloud.enabled=true" >> ./testcontainers.properties echo "testcontainers.cloud.host=cloud.testcontainers.com" >> ./testcontainers.properties echo "testcontainers.cloud.port=443" >> ./testcontainers.properties - name: Run tests with Testcontainers Cloud run: mvn verify -Dtestcontainers.cloud.enabled=true env: TESTCONTAINERS_CLOUD_TOKEN: ${{ secrets.TESTCONTAINERS_CLOUD_TOKEN }} - name: Upload test results uses: actions/upload-artifact@v4 if: always() with: name: test-results path: | target/surefire-reports/ target/failsafe-reports/ retention-days: 7 13. Test Configuration for Different Environments
package com.example.testcontainers.config; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Profile; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.utility.DockerImageName; @TestConfiguration public class TestEnvironmentConfig { @Bean @Profile("test-cloud") public PostgreSQLContainer<?> cloudPostgreSQLContainer() { return new PostgreSQLContainer<>(DockerImageName.parse("postgres:15-alpine")) .withDatabaseName("cloud_test") .withUsername("cloud_user") .withPassword("cloud_pass") .withReuse(true) .withLabel("environment", "cloud"); } @Bean @Profile("test-local") public PostgreSQLContainer<?> localPostgreSQLContainer() { return new PostgreSQLContainer<>(DockerImageName.parse("postgres:15-alpine")) .withDatabaseName("local_test") .withUsername("local_user") .withPassword("local_pass") .withReuse(false); // Don't reuse for local tests } } Best Practices
14. Test Utilities and Helpers
package com.example.testcontainers.util; import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; import java.time.Duration; public class TestContainerUtils { public static GenericContainer<?> createRedisContainer() { return new GenericContainer<>(DockerImageName.parse("redis:7-alpine")) .withExposedPorts(6379) .withStartupTimeout(Duration.ofSeconds(30)) .withCommand("redis-server", "--appendonly", "yes"); } public static GenericContainer<?> createCustomAppContainer(String image, int port, String... command) { return new GenericContainer<>(DockerImageName.parse(image)) .withExposedPorts(port) .withCopyFileToContainer( MountableFile.forClasspathResource("config/"), "/app/config/") .withCommand(command) .withStartupTimeout(Duration.ofSeconds(60)); } public static void waitForContainer(GenericContainer<?> container, String logMessage) { container.waitingFor( new org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy() .withRegEx(".*" + logMessage + ".*") ); } public static String getContainerLogs(GenericContainer<?> container) { return container.getLogs(); } } Conclusion
Testcontainers Cloud provides significant benefits for Java testing:
- Faster Test Execution: Parallel container execution in the cloud
- No Local Docker: Eliminates local Docker dependencies and resource constraints
- Consistent Environments: Same container behavior across all environments
- Scalability: Handle large test suites with multiple containers
- Advanced Networking: Simplified multi-container testing scenarios
By integrating Testcontainers Cloud with your Java testing strategy, you can achieve faster feedback cycles, more reliable tests, and better resource utilization while maintaining the power and flexibility of container-based testing.