Testcontainers Cloud in Java: Complete Guide

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:

  1. Faster Test Execution: Parallel container execution in the cloud
  2. No Local Docker: Eliminates local Docker dependencies and resource constraints
  3. Consistent Environments: Same container behavior across all environments
  4. Scalability: Handle large test suites with multiple containers
  5. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper