Skip to main content

Earlier this year Spring Boot 3.1.0 released a seamless integration with Testcontainers through ConnectionDetails and ServiceConnection abstractions. To learn more about it, please read Spring Boot Application Testing and Development with Testcontainers.

Spring Boot 3.1 already had support for many Testcontainers modules:

  • CassandraContainer
  • CouchbaseContainer
  • ElasticsearchContainer
  • GenericContainer using redis or openzipkin/zipkin
  • JdbcDatabaseContainer
  • KafkaContainer
  • MongoDBContainer
  • MariaDBContainer
  • MSSQLServerContainer
  • MySQLContainer
  • Neo4jContainer
  • OracleContainer
  • PostgreSQLContainer
  • RabbitMQContainer
  • RedpandaContainer

Now, with Spring Boot version 3.2.0 out, let’s look at what’s specifically new with the Testcontainers integration.

New ServiceConnection support

Apache ActiveMQ Classic

Testcontainers doesn’t offer any specific module for ActiveMQ, but we can just use GenericContainer, which works with any Docker image.

Using DynamicPropertySource:

@Container
static GenericContainer<?> activemq = new GenericContainer("symptoma/activemq:5.18.0").withExposedPorts(61616);

@DynamicPropertySource
static void properties(DynamicPropertyRegistry registry) {
	registry.add("spring.activemq.broker-url",
			() -> "tcp://%s:%d".formatted(activemq.getHost(), activemq.getMappedPort(61616)));
}

Using ServiceConnection:

@Container
@ServiceConnection
static GenericContainer<?> activemq = new GenericContainer("symptoma/activemq:5.18.2")
		.withExposedPorts(61616);

Recently, Apache ActiveMQ started releasing its own Docker images, and we can use it with Spring Boot as well, but since the current implementation expects the symptoma/activemq image name, we have to let Spring Boot know about it using the ServiceConnection’s name property.

@Container
@ServiceConnection(name = "symptoma/activemq")
static GenericContainer<?> activemq = new GenericContainer("apache/activemq-classic:5.18.2")
		.withExposedPorts(61616);

Why was apache/activemq-classic not supported from the beginning? Well, as the contributor of this feature at the time of raising the PR I was looking for the following features:

  1. Environment Variables for credentials
  2. Support in ARM

Support for credentials via environment variables was recently added. See apache/activemq#1114
Would you like to see a module for ActiveMQ? Follow testcontainers/testcontainers-java#7400

Apache Pulsar

Spring for Apache Pulsar is one of the most recent additions to the Spring portfolio, and it has been officially introduced in Spring Boot 3.2.0. Accordingly, support for ServiceConnection is provided from the beginning, and Testcontainers offers a module under the org.testcontainers:pulsar coordinates. 

Using DynamicPropertySource:

@Container
static PulsarContainer pulsar = new PulsarContainer(DockerImageName.parse("apachepulsar/pulsar:3.1.0"));

@DynamicPropertySource
static void pulsarProperties(DynamicPropertyRegistry registry) {
	registry.add("spring.pulsar.client.service-url", pulsar::getPulsarBrokerUrl);
	registry.add("spring.pulsar.admin.service-url", pulsar::getHttpServiceUrl);
}

Using ServiceConnection:

@ServiceConnection
static PulsarContainer pulsar = new PulsarContainer(DockerImageName.parse("apachepulsar/pulsar:3.1.0"));

OpenTelemetry Collector

Similar to ActiveMQ Classic, Testcontainers doesn’t provide a module for OpenTelemetry Collector, but again GenericContainer comes to the rescue, since we can use it with any Docker image. Spring Boot supports Metrics and Tracing for OpenTelemetry.

Using DynamicPropertySource:

@Container
static final GenericContainer<?> container = new GenericContainer<>("otel/opentelemetry-collector-contrib:0.75.0")
	.withCommand("--config=/etc/collector-config.yml")
	.withCopyToContainer(MountableFile.forClasspathResource("collector-config.yml"), "/etc/collector-config.yml")
	.withExposedPorts(4318);

@DynamicPropertySource
static void pulsarProperties(DynamicPropertyRegistry registry) {
	registry.add("management.otlp.metrics.export.url" () -> "http://%s:%d/v1/metrics".formatted(container.getHost(), container.getMappedPort(4318);
	registry.add("management.otlp.tracing.endpoint" () -> "http://%s:%d/v1/traces".formatted(container.getHost(), container.getMappedPort(4318);
}

Using ServiceConnection:

@Container
@ServiceConnection
static final GenericContainer<?> container = new GenericContainer<>("otel/opentelemetry-collector-contrib:0.75.0")
	.withCommand("--config=/etc/collector-config.yml")
	.withCopyToContainer(MountableFile.forClasspathResource("collector-config.yml"), "/etc/collector-config.yml")
	.withExposedPorts(4318, 9090);

Oracle Database Free

Testcontainers’ oracle-free module is a new addition in Testcontainers for Java 1.19.2. And given that org.testcontainers.oracle.OracleContainer extends from JdbcDatabaseContainer, it is already supported by Spring Boot’s ServiceConnection for JDBC. However, R2DBC support needed some changes which were introduced in Spring Boot 3.2.0.

Using DynamicPropertySource:

@Container
static OracleContainer oracle = new OracleContainer("gvenzl/oracle-free:23.3-slim-faststart");

@DynamicPropertySource
static void pulsarProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", oracle::getJdbcUrl);
        registry.add("spring.datasource.username", oracle::getUsername);
        registry.add("spring.datasource.password", oracle::getPassword);
}

Using ServiceConnection:

@Container
@ServiceConnection
static OracleContainer oracle = new OracleContainer("gvenzl/oracle-free:23.3-slim-faststart");

Testcontainers Beans Startup

Testcontainers allows to start containers in parallel, which can reduce the impact of the container start overhead on the overall test execution duration. Manually we can call Startables.deepStart(postgres, integresql).join(); or using Testcontainers’ JUnit Jupiter integration @Testcontainers(parallel = true). Those mechanisms work well when we are working with Testcontainers directly. In Spring Boot 3.1.0, we can create beans for all Testcontainers containers, see the official documentation, and now, in Spring Boot 3.2.0, a new property spring.testcontainers.beans.startup has been added when using the spring-boot-testcontainers module. The supported values are sequential (default) and parallel.

Note: Spring Boot 3.2.0 already provides the latest and greatest Testcontainers version, 1.19.3. Remember that we can also override and upgrade it independently using the property testcontainers.version in our build file.

Spring Boot continues to add new integrations with Testcontainers, improving the developer experience, helping developers write reliable tests and ship to production with confidence. These integrations also enable developers to recreate local development environments that work seamlessly with the databases, message brokers and other external services the app depends on.

Eddú Meléndez

Software Engineer at AtomicJar. Working on Testcontainers for Java. In 2022 became a Java Champion.