From 4e2bd93c37028004e8518b7b992b0e2e4bb24139 Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 9 Feb 2025 09:28:41 +0100 Subject: [PATCH 1/7] Document methods of starting Testcontainer containers In this commit I have documented three methods of starting containers from Testcontainer library as part of the Spring Boot tests. Signed-off-by: Vanio Begic --- .../pages/testing/testcontainers.adoc | 35 +++++++++++++++++- .../BeanDeclarationConfig.java | 34 +++++++++++++++++ .../beandeclaration/SpringTest.java | 37 +++++++++++++++++++ .../importcontainers/MyConfiguration.java | 25 +++++++++++++ .../importcontainers/MyInterface.java | 35 ++++++++++++++++++ .../beandeclaration/BeanDeclarationConfig.kt | 17 +++++++++ .../beandeclaration/SpringTest.kt | 19 ++++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyInterface.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.kt create mode 100644 spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.kt diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index d6a7d4c2e862..497cee55305e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -5,14 +5,47 @@ The https://www.testcontainers.org/[Testcontainers] library provides a way to ma It integrates with JUnit, allowing you to write a test class that can start up a container before any of the tests run. Testcontainers is especially useful for writing integration tests that talk to a real backend service such as MySQL, MongoDB, Cassandra and others. +In following sections we will describe some of the methods you can use to integrate Testcontainers with your tests. + +== Using via @Testcontainers JUnit5 extension + +The Testcontainers framework provides JUnit5 extensions, which can be used to manage containers in your tests. +The extension is activated by applying the + Testcontainers can be used in a Spring Boot test as follows: include-code::vanilla/MyIntegrationTests[] -This will start up a docker container running Neo4j (if Docker is running locally) before any of the tests are run. +This will start up a Docker container running Neo4j (if Docker is running locally) before any of the tests are run. In most cases, you will need to configure the application to connect to the service running in the container. +In this case the lifecycle of the container instance is managed by Testcontainers framework, as described in official documentation. + +== Using via Spring managed beans + +The containers provided by Testcontainers framework can be managed by Spring Boot as beans. +This method is often used in combination with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. + +To use Testcontainer contains as Spring beans we need to create a configuration class declaring the container as bean: + +include-code::beandeclaration/BeanDeclarationConfig[] + +then we can start the container by importing the configuration class in the test class: + +include-code::beandeclaration/SpringTest[] + + +== Using via importing container declaration classes + +A common pattern with Testcontainers framework is to declare the Container instances as static fields in an interface +For example the following interface `MyInterface` declares two containers, one named `mongo` of type MongoDB and another named `neo` of type Neo4j: + +include-code::importcontainers/MyInterface[] + +When you have containers declared in this way, then you can have these containers managed by Spring Boot as beans. +All that is needed to do that is adding javadoc:org.springframework.boot.testcontainers.context.ImportTestcontainers[format=annotation] to your configuration class as in: +include-code::importcontainers/MyConfiguration[] [[testing.testcontainers.service-connections]] == Service Connections diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java new file mode 100644 index 000000000000..c98c31b055a9 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.testing.testcontainers.beandeclaration; + +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; + +@TestConfiguration(proxyBeanMethods = false) +class BeanDeclarationConfig { + + @ServiceConnection + @Bean + MongoDBContainer container() { + return new MongoDBContainer(DockerImageName.parse("mongo:latest")); + } +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java new file mode 100644 index 000000000000..7afaa9742b5f --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.testing.testcontainers.beandeclaration; + +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; + +@SpringBootTest +@Import(BeanDeclarationConfig.class) +public class SpringTest { + + @Autowired + private MongoDBContainer mongo; + + @Test + void doTest() { + System.out.println("Mongo db is running: " + this.mongo.isRunning()); + } +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java new file mode 100644 index 000000000000..481ba7d3871a --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.testing.testcontainers.importcontainers; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.context.ImportTestcontainers; + +@TestConfiguration(proxyBeanMethods = false) +@ImportTestcontainers(MyInterface.class) +class MyConfiguration { +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyInterface.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyInterface.java new file mode 100644 index 000000000000..b00f693277d7 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyInterface.java @@ -0,0 +1,35 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.testing.testcontainers.importcontainers; + +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; + +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +interface MyInterface { + + @Container + @ServiceConnection + MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0"); + + @Container + @ServiceConnection + Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:5"); + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.kt b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.kt new file mode 100644 index 000000000000..ddbce31e75d8 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.kt @@ -0,0 +1,17 @@ +package org.springframework.boot.docs.testing.testcontainers.beandeclaration + +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.boot.testcontainers.service.connection.ServiceConnection +import org.springframework.context.annotation.Bean +import org.testcontainers.containers.MongoDBContainer +import org.testcontainers.utility.DockerImageName + + +@TestConfiguration(proxyBeanMethods = false) +internal class BeanDeclarationConfig { + @ServiceConnection + @Bean + fun container(): MongoDBContainer { + return MongoDBContainer(DockerImageName.parse("mongo:latest")) + } +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.kt b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.kt new file mode 100644 index 000000000000..edb36d9cf088 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.kt @@ -0,0 +1,19 @@ +package org.springframework.boot.docs.testing.testcontainers.beandeclaration + +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Import +import org.testcontainers.containers.MongoDBContainer + +@SpringBootTest +@Import(BeanDeclarationConfig::class) +class SpringTest { + @Autowired + private val mongo: MongoDBContainer? = null + + @Test + fun doTest() { + println("Mongo db is running: " + mongo!!.isRunning) + } +} \ No newline at end of file From 64d82a5cd46a72ac40d803c2f469308dddc4f882 Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 9 Feb 2025 16:45:55 +0100 Subject: [PATCH 2/7] Add information about lifecycle of testcontainers to documentation Signed-off-by: Vanio Begic --- .../pages/testing/testcontainers.adoc | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index 497cee55305e..e59f125a425c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -47,6 +47,28 @@ All that is needed to do that is adding javadoc:org.springframework.boot.testcon include-code::importcontainers/MyConfiguration[] +== Lifecycle of managed containers + +If you have used the annotations and extensions provided by Testcontainers framework, then the lifecycle of container instances is managed by the Testcontainers framework. +Please refer to the official documentation for the information about lifecycle of the containers, when managed by the Testcontainers framework. + +When the containers are managed by Spring as beans, then the lifecycle is clearly defined by Spring. +The container beans are created and started before the beans of other types are created. +This process ensures that any beans, which rely on functionality provided by the containers, can use those functionalities. + +The test containers can be started multiple times. +Like any other beans the test containers are created and started once per application context managed by the TestContext Framework. +For details about how TestContext framework manages the underlying application contexts and beans therein, please refer to the official Spring documentation. + +The container beans are stopped after the destruction of beans of other types. +This ensures that any beans depending on the functionalities provided by the containers are cleaned up first. + +The containers are stopped as part of the application shutdown process, managed by the TestContext framework. +When the application context gets shutdown, the containers are shutdown as well. +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. + +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. + [[testing.testcontainers.service-connections]] == Service Connections From b50570f9ed6f1cc1be1af9619cf3b199d056a61f Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 9 Feb 2025 22:24:44 +0100 Subject: [PATCH 3/7] Fix formatting and add necessary suppressions Closes #43738 Signed-off-by: Vanio Begic --- .../testcontainers/beandeclaration/BeanDeclarationConfig.java | 1 + .../testing/testcontainers/beandeclaration/SpringTest.java | 3 ++- .../testcontainers/importcontainers/MyConfiguration.java | 1 + src/checkstyle/checkstyle-suppressions.xml | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java index c98c31b055a9..7a1e4e5e7c83 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/BeanDeclarationConfig.java @@ -31,4 +31,5 @@ class BeanDeclarationConfig { MongoDBContainer container() { return new MongoDBContainer(DockerImageName.parse("mongo:latest")); } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java index 7afaa9742b5f..4f98ba476f09 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/beandeclaration/SpringTest.java @@ -25,7 +25,7 @@ @SpringBootTest @Import(BeanDeclarationConfig.class) -public class SpringTest { +class SpringTest { @Autowired private MongoDBContainer mongo; @@ -34,4 +34,5 @@ public class SpringTest { void doTest() { System.out.println("Mongo db is running: " + this.mongo.isRunning()); } + } diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java index 481ba7d3871a..2b3857fb9ccb 100644 --- a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importcontainers/MyConfiguration.java @@ -22,4 +22,5 @@ @TestConfiguration(proxyBeanMethods = false) @ImportTestcontainers(MyInterface.class) class MyConfiguration { + } diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index d44eac1e47ed..6456782f31dc 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -82,6 +82,7 @@ + From 668e136567eb3b3020c27324075e4f17b7f973ce Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 16 Feb 2025 08:38:09 +0100 Subject: [PATCH 4/7] Replace 'Testcontainers framework' with just 'Testcontainers' Signed-off-by: Vanio Begic --- .../reference/pages/testing/testcontainers.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index e59f125a425c..83d3e0940e77 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -9,7 +9,7 @@ In following sections we will describe some of the methods you can use to integr == Using via @Testcontainers JUnit5 extension -The Testcontainers framework provides JUnit5 extensions, which can be used to manage containers in your tests. +The Testcontainers provides JUnit5 extensions, which can be used to manage containers in your tests. The extension is activated by applying the Testcontainers can be used in a Spring Boot test as follows: @@ -19,11 +19,11 @@ include-code::vanilla/MyIntegrationTests[] This will start up a Docker container running Neo4j (if Docker is running locally) before any of the tests are run. In most cases, you will need to configure the application to connect to the service running in the container. -In this case the lifecycle of the container instance is managed by Testcontainers framework, as described in official documentation. +In this case the lifecycle of the container instance is managed by Testcontainers, as described in official documentation. == Using via Spring managed beans -The containers provided by Testcontainers framework can be managed by Spring Boot as beans. +The containers provided by Testcontainers can be managed by Spring Boot as beans. This method is often used in combination with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. To use Testcontainer contains as Spring beans we need to create a configuration class declaring the container as bean: @@ -37,7 +37,7 @@ include-code::beandeclaration/SpringTest[] == Using via importing container declaration classes -A common pattern with Testcontainers framework is to declare the Container instances as static fields in an interface +A common pattern with Testcontainers is to declare the Container instances as static fields in an interface For example the following interface `MyInterface` declares two containers, one named `mongo` of type MongoDB and another named `neo` of type Neo4j: include-code::importcontainers/MyInterface[] @@ -49,8 +49,8 @@ include-code::importcontainers/MyConfiguration[] == Lifecycle of managed containers -If you have used the annotations and extensions provided by Testcontainers framework, then the lifecycle of container instances is managed by the Testcontainers framework. -Please refer to the official documentation for the information about lifecycle of the containers, when managed by the Testcontainers framework. +If you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed by the Testcontainers. +Please refer to the official documentation for the information about lifecycle of the containers, when managed by the Testcontainers. When the containers are managed by Spring as beans, then the lifecycle is clearly defined by Spring. The container beans are created and started before the beans of other types are created. From af345d3fc795bc423cfa70a7178e7329508eb195 Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 16 Feb 2025 09:08:13 +0100 Subject: [PATCH 5/7] Improve wording and add tips and notes where appropriate Signed-off-by: Vanio Begic --- .../antora-asciidoc-attributes.properties | 1 + .../pages/testing/testcontainers.adoc | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties index 82eba8024b6b..2b8362af115f 100644 --- a/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties +++ b/buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties @@ -75,6 +75,7 @@ url-spring-data-rest-docs=https://docs.spring.io/spring-data/rest/reference/{ant url-spring-data-rest-site=https://spring.io/projects/spring-data-rest url-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{dotxversion-spring-data-rest}/api url-spring-data-site=https://spring.io/projects/spring-data +url-testcontainers-java-doc=https://java.testcontainers.org url-testcontainers-activemq-javadoc=https://javadoc.io/doc/org.testcontainers/activemq/{version-testcontainers-activemq} url-testcontainers-cassandra-javadoc=https://javadoc.io/doc/org.testcontainers/cassandra/{version-testcontainers-cassandra} url-testcontainers-couchbase-javadoc=https://javadoc.io/doc/org.testcontainers/couchbase/{version-testcontainers-couchbase} diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index 83d3e0940e77..bdf8955402e6 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -24,7 +24,7 @@ In this case the lifecycle of the container instance is managed by Testcontainer == Using via Spring managed beans The containers provided by Testcontainers can be managed by Spring Boot as beans. -This method is often used in combination with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. +This method of managing contains can be used in combination with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation]. To use Testcontainer contains as Spring beans we need to create a configuration class declaring the container as bean: @@ -37,7 +37,7 @@ include-code::beandeclaration/SpringTest[] == Using via importing container declaration classes -A common pattern with Testcontainers is to declare the Container instances as static fields in an interface +A common pattern with Testcontainers is to declare the Container instances as static fields in an interface. For example the following interface `MyInterface` declares two containers, one named `mongo` of type MongoDB and another named `neo` of type Neo4j: include-code::importcontainers/MyInterface[] @@ -47,10 +47,13 @@ All that is needed to do that is adding javadoc:org.springframework.boot.testcon include-code::importcontainers/MyConfiguration[] +TIP: Using interfaces for declaring contains helps with reuse. +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. + == Lifecycle of managed containers If you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed by the Testcontainers. -Please refer to the official documentation for the information about lifecycle of the containers, when managed by the Testcontainers. +Please refer to the {url-testcontainres-java-doc}[Testcontainers official documentation] for the information about lifecycle of the containers, when managed by the Testcontainers. When the containers are managed by Spring as beans, then the lifecycle is clearly defined by Spring. The container beans are created and started before the beans of other types are created. @@ -58,11 +61,19 @@ This process ensures that any beans, which rely on functionality provided by the The test containers can be started multiple times. Like any other beans the test containers are created and started once per application context managed by the TestContext Framework. -For details about how TestContext framework manages the underlying application contexts and beans therein, please refer to the official Spring documentation. +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]. The container beans are stopped after the destruction of beans of other types. This ensures that any beans depending on the functionalities provided by the containers are cleaned up first. +TIP: When your application beans rely on functionality of containers, prefer configuring the containers as Spring beans. +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. +On shutdown the application beans depending on container functionalities are cleaned up first, and only then are the containers shut down. + +NOTE: Having containers managed by Testcontainers instead of as Spring beans provides no guarantee of order in which beans and containers will shutdown. +It can happen that containers are shutdown before the beans relying on container functionality are cleaned up. +This can lead to exceptions being thrown by client beans due to loss of connection for example. + The containers are stopped as part of the application shutdown process, managed by the TestContext framework. When the application context gets shutdown, the containers are shutdown as well. 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. From b8652162938f1e47b3e7b0b6fe3e60086ce804a8 Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sun, 16 Feb 2025 09:34:57 +0100 Subject: [PATCH 6/7] Improve formatting according to the requirements in Wiki Concretely I have ensured that there are three lines between text and next header. Also I added anchors to each header Signed-off-by: Vanio Begic --- .../reference/pages/testing/testcontainers.adoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index bdf8955402e6..487ead8c7aa0 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -7,6 +7,9 @@ Testcontainers is especially useful for writing integration tests that talk to a In following sections we will describe some of the methods you can use to integrate Testcontainers with your tests. + + +[[testing.testcontainers.via-junit-extension]] == Using via @Testcontainers JUnit5 extension The Testcontainers provides JUnit5 extensions, which can be used to manage containers in your tests. @@ -21,6 +24,8 @@ In most cases, you will need to configure the application to connect to the serv In this case the lifecycle of the container instance is managed by Testcontainers, as described in official documentation. + +[[testing.testcontainers.via-spring-beans]] == Using via Spring managed beans The containers provided by Testcontainers can be managed by Spring Boot as beans. @@ -35,6 +40,7 @@ then we can start the container by importing the configuration class in the test include-code::beandeclaration/SpringTest[] +[[testing.testcontainers.via-declaration-classes]] == Using via importing container declaration classes A common pattern with Testcontainers is to declare the Container instances as static fields in an interface. @@ -50,6 +56,8 @@ include-code::importcontainers/MyConfiguration[] TIP: Using interfaces for declaring contains helps with reuse. 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. + +[[test.testcontainers.container-lifecycle]] == Lifecycle of managed containers If you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed by the Testcontainers. @@ -80,6 +88,8 @@ This usually happens after all tests using that specific cached application cont 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. + + [[testing.testcontainers.service-connections]] == Service Connections From 92efef46588187490356a078fbd59c90186672b5 Mon Sep 17 00:00:00 2001 From: Vanio Begic Date: Sat, 22 Feb 2025 23:14:05 +0100 Subject: [PATCH 7/7] Complete the omitted sentence Signed-off-by: Vanio Begic --- .../antora/modules/reference/pages/testing/testcontainers.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index 487ead8c7aa0..ef72b0d2616c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -13,7 +13,7 @@ In following sections we will describe some of the methods you can use to integr == Using via @Testcontainers JUnit5 extension The Testcontainers provides JUnit5 extensions, which can be used to manage containers in your tests. -The extension is activated by applying the +The extension is activated by applying the `@Testcontainers` annotation from Testcontainers to your test class. Testcontainers can be used in a Spring Boot test as follows: