Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll learn how to reuse Testcontainers when setting up the environment for local development and testing.

Firstly, we’ll have to make sure we’re not shutting down the container when the application is stopped or when the test suite finishes. After that, we’ll talk about the Testcontainerspecific configuration and we’ll discuss the benefits of using the Testcontainers Desktop application. Lastly, we need to keep in mind that reusing Testcontainers is an experimental feature and it’s not yet ready to be used in CI pipelines.

2. Ensure the Testcontainer Isn’t Stopped

A straightforward way of enabling Testcontainers for our unit tests is to leverage their dedicated JUnit 5 extension through the @Testcontainers and @Container annotations.

Let’s write a test that starts a Spring Boot application and allows it to connect to a MongoDB database running in a Docker container:

@Testcontainers
@SpringBootTest
class ReusableContainersLiveTest {

    @Container
    static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"));
  
    // dynamic properties and test cases
}

However, the Testcontainer’s JUnit5 Extension that automatically spins up MongoDBContainer will also shuts it down after the tests. Therefore, let’s remove the @Testcontainers and @Container annotations, and manually start the container instead:

@SpringBootTest
class ReusableContainersLiveTest {
   static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"));

    @BeforeAll
    static void beforeAll() {
        mongoDBContainer.start();
    }
    
    // dynamic properties and test cases
}

On the other hand, we might be using Spring Boot’s built-in support for Testcontainers during local development. In this context, we won’t use the JUnit 5 extension and this step is unnecessary.

3. Manage the Testcontainer Lifecycle

Now, we can be in full control of the container’s lifecycle. We can configure the application to reuse an existing Testcontainer and we can manually stop it from the terminal.

3.1. The withReuse() Method

We can mark a Testcontainer as reusable by using the withReuse() method of its fluent API:

static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))
  .withReuse(true);

When we run the test for the first time, we’ll see the usual Testcontainers logs about starting the MongoDBContainer. This usually takes a few seconds:

23:56:42.383 [main] INFO tc.mongo:4.0.10 - Creating container for image: mongo:4.0.10
23:56:42.892 [main] INFO tc.mongo:4.0.10 - Container mongo:4.0.10 is starting: d5fa298bf6...
23:56:45.470 [main] INFO tc.mongo:4.0.10 - Container mongo:4.0.10 started in PT3.11239S

After the test finishes, we should be able to see the container still running. For example, we can check from the terminal using the docker ps command:

Reusing Testcontainers

 

Furthermore, when we re-run the test, the container will be reused as long as the configuration isn’t changed. As a result, the container set-up time noticeably decreases:

00:12:23.859 [main] INFO tc.mongo:4.0.10 - Creating container for image: mongo:4.0.10
00:12:24.190 [main] INFO tc.mongo:4.0.10 - Reusing container with ID: d5fa298b... and hash: 0702144b...
00:12:24.191 [main] INFO tc.mongo:4.0.10 - Reusing existing container (d5fa298b...) and not creating a new one
00:12:24.398 [main] INFO tc.mongo:4.0.10 - Container mongo:4.0.10 started in PT0.5555088S

Lastly, the reused database contains previously inserted documents. Although this might be useful for local development, it may be harmful for testing. If we need to start fresh, we can simply clear the collection before each test.

3.2. Testcontainers Configuration

In some cases, a warning may occur, stating that “Reuse was requested but the environment doesn’t support the reuse of containers”. This happens when the reuse is disabled on our local Testcontainers configuration:

00:23:09.461 [main] INFO tc.mongo:4.0.10 - Creating container for image: mongo:4.0.10
00:23:09.463 [main] WARN tc.mongo:4.0.10 - Reuse was requested but the environment does not support the reuse of containers
To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at C:\Users\Emanuel Trandafir\.testcontainers.properties
00:23:09.544 [main] INFO tc.mongo:4.0.10 - Container mongo:4.0.10 is starting: 903dd52d7...

To fix it, we can simply edit the .testcontainers.properties file and set reuse as enabled:

 

Enable TC Reuse from Properties

3.3. Stopping the Container

We can manually stop the Docker container whenever we want, from the terminal. To do so, we only need to run the docker stop command, followed by the container ID. Future executions of the application spin up a new Docker container.

4. Testcontainers Desktop

We can install the Testcontainer Desktop application to easily manage the lifecycle and configuration of our Testcontainers.

The application requires authentication, but we can easily log in using a GitHub account. After signing in, we’ll see the Testcontainers icon in the toolbar. If we click on it, we’ll have a few options to choose from:

 

Testcontainers

Now, executing the previously demonstrated steps is as effortless as the click of a button. For instance, we can enable or disable reusable containers with ease via Preferences > Enable reusable containers. Furthermore, we have the capability to terminate the containers or freeze them before the shutdown, if more debugging is needed.

5. Conclusion

In this article, we’ve learned how to reuse Testcontainers in Java. We discovered that JUnit 5 might try to shut down the container before finishing the execution. We avoided this by manually starting the containers instead of relying on the Testcontainers’ JUnit 5 extension.

After that, we discussed the withReuse() method and other Testcontainer-specific configurations. Finally, we installed the Testcontainers Desktop application, and we saw how it can be a valuable asset for double-checking configurations when it comes to managing the Testcontainers’ lifecycle.

As always, the complete code used in this article is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.