Skip to content

Commit 8814d8a

Browse files
committed
Polish 'Document methods of starting Testcontainer containers'
See gh-44187
1 parent 4a98b17 commit 8814d8a

File tree

18 files changed

+208
-114
lines changed

18 files changed

+208
-114
lines changed

buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ url-spring-data-rest-docs=https://docs.spring.io/spring-data/rest/reference/{ant
7575
url-spring-data-rest-site=https://spring.io/projects/spring-data-rest
7676
url-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{dotxversion-spring-data-rest}/api
7777
url-spring-data-site=https://spring.io/projects/spring-data
78-
url-testcontainers-java-doc=https://java.testcontainers.org
78+
url-testcontainers-docs=https://java.testcontainers.org
7979
url-testcontainers-activemq-javadoc=https://javadoc.io/doc/org.testcontainers/activemq/{version-testcontainers-activemq}
8080
url-testcontainers-cassandra-javadoc=https://javadoc.io/doc/org.testcontainers/cassandra/{version-testcontainers-cassandra}
8181
url-testcontainers-couchbase-javadoc=https://javadoc.io/doc/org.testcontainers/couchbase/{version-testcontainers-couchbase}

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc

Lines changed: 52 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,85 +8,90 @@ Testcontainers is especially useful for writing integration tests that talk to a
88
In following sections we will describe some of the methods you can use to integrate Testcontainers with your tests.
99

1010

11+
[[testing.testcontainers.spring-beans]]
12+
== Using Spring Beans
1113

12-
[[testing.testcontainers.via-junit-extension]]
13-
== Using via @Testcontainers JUnit5 extension
14+
The containers provided by Testcontainers can be managed by Spring Boot as beans.
1415

15-
The Testcontainers provides JUnit5 extensions, which can be used to manage containers in your tests.
16-
The extension is activated by applying the `@Testcontainers` annotation from Testcontainers to your test class.
16+
To declare a container as a bean, add a javadoc:org.springframework.context.annotation.Bean[format=annotation] method to your test configuration:
1717

18-
Testcontainers can be used in a Spring Boot test as follows:
18+
include-code::MyTestConfiguration[]
1919

20-
include-code::vanilla/MyIntegrationTests[]
20+
You can then inject and use the container by importing the configuration class in the test class:
2121

22-
This will start up a Docker container running Neo4j (if Docker is running locally) before any of the tests are run.
23-
In most cases, you will need to configure the application to connect to the service running in the container.
22+
include-code::MyIntegrationTests[]
2423

25-
In this case the lifecycle of the container instance is managed by Testcontainers, as described in official documentation.
24+
TIP: This method of managing containers is often used in combination with xref:#testing.testcontainers.service-connections[service connection annotations].
2625

2726

28-
[[testing.testcontainers.via-spring-beans]]
29-
== Using via Spring managed beans
3027

31-
The containers provided by Testcontainers can be managed by Spring Boot as beans.
32-
This method of managing contains can be used in combination with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation].
28+
[[testing.testcontainers.junit-extension]]
29+
== Using the JUnit Extension
3330

34-
To use Testcontainer contains as Spring beans we need to create a configuration class declaring the container as bean:
31+
Testcontainers provides a JUnit extension which can be used to manage containers in your tests.
32+
The extension is activated by applying the javadoc:org.testcontainers.junit.jupiter.Testcontainers[format=annotation] annotation from Testcontainers to your test class.
3533

36-
include-code::beandeclaration/BeanDeclarationConfig[]
34+
You can then use the javadoc:org.testcontainers.junit.jupiter.Container[format=annotation] annotation on static container fields.
3735

38-
then we can start the container by importing the configuration class in the test class:
36+
The javadoc:org.testcontainers.junit.jupiter.Testcontainers[format=annotation] annotation can be used on vanilla JUnit tests, or in combination with javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation]:
3937

40-
include-code::beandeclaration/SpringTest[]
38+
include-code::MyIntegrationTests[]
4139

40+
The example above will start up a Neo4j container before any of the tests are run.
41+
The lifecycle of the container instance is managed by Testcontainers, as described in {url-testcontainers-docs}/test_framework_integration/junit_5/#extension[their official documentation].
4242

43-
[[testing.testcontainers.via-declaration-classes]]
44-
== Using via importing container declaration classes
43+
NOTE: In most cases, you will additionally need to configure the application to connect to the service running in the container.
4544

46-
A common pattern with Testcontainers is to declare the Container instances as static fields in an interface.
47-
For example the following interface `MyInterface` declares two containers, one named `mongo` of type MongoDB and another named `neo` of type Neo4j:
4845

49-
include-code::importcontainers/MyInterface[]
5046

51-
When you have containers declared in this way, then you can have these containers managed by Spring Boot as beans.
52-
All that is needed to do that is adding javadoc:org.springframework.boot.testcontainers.context.ImportTestcontainers[format=annotation] to your configuration class as in:
47+
[[testing.testcontainers.importing-configuration-interfaces]]
48+
== Importing Container Configuration Interfaces
5349

54-
include-code::importcontainers/MyConfiguration[]
50+
A common pattern with Testcontainers is to declare the container instances as static fields in an interface.
5551

56-
TIP: Using interfaces for declaring contains helps with reuse.
57-
When containers are declared in an interface, this can be reused in your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes and in test classes.
52+
For example, the following interface declares two containers, one named `mongo` of type javadoc:org.testcontainers.containers.MongoDBContainer[] and another named `neo4j` of type javadoc:org.testcontainers.containers.Neo4jContainer.Neo4jContainer[]:
5853

54+
include-code::MyContainers[]
5955

60-
[[test.testcontainers.container-lifecycle]]
61-
== Lifecycle of managed containers
56+
When you have containers declared in this way, you can reuse their configuration in multiple tests by having the test classes implement the interface.
57+
58+
It's also possible to use the same interface configuration in your Spring Boot tests.
59+
To do so, add javadoc:org.springframework.boot.testcontainers.context.ImportTestcontainers[format=annotation] to your test configuration class:
60+
61+
include-code::MyTestConfiguration[]
6262

63-
If you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed by the Testcontainers.
64-
Please refer to the {url-testcontainres-java-doc}[Testcontainers official documentation] for the information about lifecycle of the containers, when managed by the Testcontainers.
6563

66-
When the containers are managed by Spring as beans, then the lifecycle is clearly defined by Spring.
67-
The container beans are created and started before the beans of other types are created.
68-
This process ensures that any beans, which rely on functionality provided by the containers, can use those functionalities.
6964

70-
The test containers can be started multiple times.
71-
Like any other beans the test containers are created and started once per application context managed by the TestContext Framework.
72-
For details about how TestContext framework manages the underlying application contexts and beans therein, please refer to the {url-spring-framework-docs}[official Spring documentation].
65+
[[testing.testcontainers.lifecycle]]
66+
== Lifecycle of Managed Containers
7367

74-
The container beans are stopped after the destruction of beans of other types.
75-
This ensures that any beans depending on the functionalities provided by the containers are cleaned up first.
68+
If you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed entirely by Testcontainers.
69+
Please refer to the {url-testcontainers-docs}[offical Testcontainers documentation] for the information.
7670

77-
TIP: When your application beans rely on functionality of containers, prefer configuring the containers as Spring beans.
78-
When containers are managed as Spring beans, then Spring framework ensures that upon start the container beans are started before any beans relying on them.
79-
On shutdown the application beans depending on container functionalities are cleaned up first, and only then are the containers shut down.
71+
When the containers are managed by Spring as beans, then their lifecycle is managed by Spring:
8072

81-
NOTE: Having containers managed by Testcontainers instead of as Spring beans provides no guarantee of order in which beans and containers will shutdown.
73+
* Container beans are created and started before all other beans.
74+
75+
* Container beans are stopped after the destruction of all other beans.
76+
77+
This process ensures that any beans, which rely on functionality provided by the containers, can use those functionalities.
78+
It also ensures that they are cleaned up whilst the container is still available.
79+
80+
TIP: When your application beans rely on functionality of containers, prefer configuring the containers as Spring beans to ensure the correct lifecycle behavior.
81+
82+
NOTE: Having containers managed by Testcontainers instead of as Spring beans provides no guarantee of the order in which beans and containers will shutdown.
8283
It can happen that containers are shutdown before the beans relying on container functionality are cleaned up.
83-
This can lead to exceptions being thrown by client beans due to loss of connection for example.
84+
This can lead to exceptions being thrown by client beans, for example, due to loss of connection.
85+
86+
Container beans are created and started once per application context managed by Spring's TestContext Framework.
87+
For details about how TestContext Framework manages the underlying application contexts and beans therein, please refer to the {url-spring-framework-docs}[Spring Framework documentation].
8488

85-
The containers are stopped as part of the application shutdown process, managed by the TestContext framework.
89+
Container beans are stopped as part of the TestContext Framework's standard application context shutdown process.
8690
When the application context gets shutdown, the containers are shutdown as well.
87-
This usually happens after all tests using that specific cached application context have finished executing, but may happen earlier depending on the caching behavior configured in TestContext Framework.
91+
This usually happens after all tests using that specific cached application context have finished executing.
92+
It may also happen earlier, depending on the caching behavior configured in TestContext Framework.
8893

89-
It is important to note that a single test container instance can be, and often is, retained across execution of tests from multiple test classes.
94+
NOTE: A single test container instance can, and often is, retained across execution of tests from multiple test classes.
9095

9196

9297

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,18 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.testing.testcontainers.importcontainers;
17+
package org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces;
1818

1919
import org.testcontainers.containers.MongoDBContainer;
2020
import org.testcontainers.containers.Neo4jContainer;
2121
import org.testcontainers.junit.jupiter.Container;
2222

23-
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
24-
25-
interface MyInterface {
23+
interface MyContainers {
2624

2725
@Container
28-
@ServiceConnection
2926
MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");
3027

3128
@Container
32-
@ServiceConnection
3329
Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:5");
3430

3531
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.testing.testcontainers.importcontainers;
17+
package org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces;
1818

1919
import org.springframework.boot.test.context.TestConfiguration;
2020
import org.springframework.boot.testcontainers.context.ImportTestcontainers;
2121

2222
@TestConfiguration(proxyBeanMethods = false)
23-
@ImportTestcontainers(MyInterface.class)
24-
class MyConfiguration {
23+
@ImportTestcontainers(MyContainers.class)
24+
class MyTestConfiguration {
2525

2626
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.testing.testcontainers.vanilla;
17+
package org.springframework.boot.docs.testing.testcontainers.junitextension;
1818

1919
import org.junit.jupiter.api.Test;
2020
import org.testcontainers.containers.Neo4jContainer;
@@ -32,7 +32,7 @@ class MyIntegrationTests {
3232

3333
@Test
3434
void myTest() {
35-
// ...
35+
/**/ System.out.println(neo4j);
3636
}
3737

3838
}

spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/MyIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ class MyIntegrationTests {
3434

3535
@Test
3636
void myTest() {
37-
// ...
37+
/**/ System.out.println(neo4j);
3838
}
3939

4040
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.testing.testcontainers.beandeclaration;
17+
package org.springframework.boot.docs.testing.testcontainers.springbeans;
1818

1919
import org.junit.jupiter.api.Test;
2020
import org.testcontainers.containers.MongoDBContainer;
@@ -24,15 +24,15 @@
2424
import org.springframework.context.annotation.Import;
2525

2626
@SpringBootTest
27-
@Import(BeanDeclarationConfig.class)
28-
class SpringTest {
27+
@Import(MyTestConfiguration.class)
28+
class MyIntegrationTests {
2929

3030
@Autowired
3131
private MongoDBContainer mongo;
3232

3333
@Test
34-
void doTest() {
35-
System.out.println("Mongo db is running: " + this.mongo.isRunning());
34+
void myTest() {
35+
/**/ System.out.println(this.mongo);
3636
}
3737

3838
}
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,20 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.docs.testing.testcontainers.beandeclaration;
17+
package org.springframework.boot.docs.testing.testcontainers.springbeans;
1818

1919
import org.testcontainers.containers.MongoDBContainer;
2020
import org.testcontainers.utility.DockerImageName;
2121

2222
import org.springframework.boot.test.context.TestConfiguration;
23-
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
2423
import org.springframework.context.annotation.Bean;
2524

2625
@TestConfiguration(proxyBeanMethods = false)
27-
class BeanDeclarationConfig {
26+
class MyTestConfiguration {
2827

29-
@ServiceConnection
3028
@Bean
31-
MongoDBContainer container() {
32-
return new MongoDBContainer(DockerImageName.parse("mongo:latest"));
29+
MongoDBContainer mongoDbContainer() {
30+
return new MongoDBContainer(DockerImageName.parse("mongo:5.0"));
3331
}
3432

3533
}

spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.kt

Lines changed: 0 additions & 19 deletions
This file was deleted.

spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/dynamicproperties/MyIntegrationTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class MyIntegrationTests {
2929

3030
@Test
3131
fun myTest() {
32-
// ...
32+
/**/ println()
3333
}
3434

3535
companion object {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces
18+
19+
import org.testcontainers.containers.MongoDBContainer
20+
import org.testcontainers.containers.Neo4jContainer
21+
import org.testcontainers.junit.jupiter.Container
22+
23+
interface MyContainers {
24+
25+
companion object {
26+
27+
@Container
28+
val mongoContainer: MongoDBContainer = MongoDBContainer("mongo:5.0")
29+
30+
@Container
31+
val neo4jContainer: Neo4jContainer<*> = Neo4jContainer("neo4j:5")
32+
33+
}
34+
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces
18+
19+
import org.springframework.boot.test.context.TestConfiguration
20+
import org.springframework.boot.testcontainers.context.ImportTestcontainers
21+
22+
@TestConfiguration(proxyBeanMethods = false)
23+
@ImportTestcontainers(MyContainers::class)
24+
class MyTestConfiguration {
25+
26+
}

0 commit comments

Comments
 (0)