94 lines
5.6 KiB
Plaintext
94 lines
5.6 KiB
Plaintext
[[features.testcontainers]]
|
|
== Testcontainers Support
|
|
As well as <<features#features.testing.testcontainers, using Testcontainers for integration testing>>, it's also possible to use them at development time.
|
|
The next sections will provide more details about that.
|
|
|
|
|
|
|
|
[[features.testcontainers.at-development-time]]
|
|
=== Using Testcontainers at Development Time
|
|
This approach allows developers to quickly start containers for the services that the application depends on, removing the need to manually provision things like database servers.
|
|
Using Testcontainers in this way provides functionality similar to Docker Compose, except that your container configuration is in Java rather than YAML.
|
|
|
|
To use Testcontainers at development time you need to launch your application using your "`test`" classpath rather than "`main`".
|
|
This will allow you to access all declared test dependencies and give you a natural place to write your test configuration.
|
|
|
|
To create a test launchable version of your application you should create an "`Application`" class in the `src/test` directory.
|
|
For example, if your main application is in `src/main/java/com/example/MyApplication.java`, you should create `src/test/java/com/example/TestMyApplication.java`
|
|
|
|
The `TestMyApplication` class can use the `SpringApplication.from(...)` method to launch the real application:
|
|
|
|
include::code:launch/TestMyApplication[]
|
|
|
|
You'll also need to define the `Container` instances that you want to start along with your application.
|
|
To do this, you need to make sure that the `spring-boot-testcontainers` module has been added as a `test` dependency.
|
|
Once that has been done, you can create a `@TestConfiguration` class that declares `@Bean` methods for the containers you want to start.
|
|
|
|
You can also annotate your `@Bean` methods with `@ServiceConnection` in order to create `ConnectionDetails` beans.
|
|
See <<features#features.testing.testcontainers.service-connections, the service connections>> section for details of the supported technologies.
|
|
|
|
A typical Testcontainers configuration would look like this:
|
|
|
|
include::code:test/MyContainersConfiguration[]
|
|
|
|
NOTE: The lifecycle of `Container` beans is automatically managed by Spring Boot.
|
|
Containers will be started and stopped automatically.
|
|
|
|
TIP: You can use the configprop:spring.testcontainers.beans.startup[] property to change how containers are started.
|
|
By default `sequential` startup is used, but you may also choose `parallel` if you wish to start multiple containers in parallel.
|
|
|
|
Once you have defined your test configuration, you can use the `with(...)` method to attach it to your test launcher:
|
|
|
|
include::code:test/TestMyApplication[]
|
|
|
|
You can now launch `TestMyApplication` as you would any regular Java `main` method application to start your application and the containers that it needs to run.
|
|
|
|
TIP: You can use the Maven goal `spring-boot:test-run` or the Gradle task `bootTestRun` to do this from the command line.
|
|
|
|
|
|
|
|
[[features.testcontainers.at-development-time.dynamic-properties]]
|
|
==== Contributing Dynamic Properties at Development Time
|
|
If you want to contribute dynamic properties at development time from your `Container` `@Bean` methods, you can do so by injecting a `DynamicPropertyRegistry`.
|
|
This works in a similar way to the <<features#features.testing.testcontainers.dynamic-properties,`@DynamicPropertySource` annotation>> that you can use in your tests.
|
|
It allows you to add properties that will become available once your container has started.
|
|
|
|
A typical configuration would look like this:
|
|
|
|
include::code:MyContainersConfiguration[]
|
|
|
|
NOTE: Using a `@ServiceConnection` is recommended whenever possible, however, dynamic properties can be a useful fallback for technologies that don't yet have `@ServiceConnection` support.
|
|
|
|
|
|
|
|
[[features.testcontainers.at-development-time.importing-container-declarations]]
|
|
==== Importing Testcontainer Declaration Classes
|
|
A common pattern when using Testcontainers is to declare `Container` instances as static fields.
|
|
Often these fields are defined directly on the test class.
|
|
They can also be declared on a parent class or on an interface that the test implements.
|
|
|
|
For example, the following `MyContainers` interface declares `mongo` and `neo4j` containers:
|
|
|
|
include::code:MyContainers[]
|
|
|
|
If you already have containers defined in this way, or you just prefer this style, you can import these declaration classes rather than defining you containers as `@Bean` methods.
|
|
To do so, add the `@ImportTestcontainers` annotation to your test configuration class:
|
|
|
|
include::code:MyContainersConfiguration[]
|
|
|
|
TIP: If you don't intend to use the <<features#features.testing.testcontainers.service-connections, service connections feature>> but want to use <<features#features.testing.testcontainers.dynamic-properties, `@DynamicPropertySource`>> instead, remove the `@ServiceConnection` annotation from the `Container` fields.
|
|
You can also add `@DynamicPropertySource` annotated methods to your declaration class.
|
|
|
|
|
|
|
|
[[features.testcontainers.at-development-time.devtools]]
|
|
==== Using DevTools with Testcontainers at Development Time
|
|
When using devtools, you can annotate beans and bean methods with `@RestartScope`.
|
|
Such beans won't be recreated when the devtools restart the application.
|
|
This is especially useful for Testcontainer `Container` beans, as they keep their state despite the application restart.
|
|
|
|
include::code:MyContainersConfiguration[]
|
|
|
|
WARNING: If you're using Gradle and want to use this feature, you need to change the configuration of the `spring-boot-devtools` dependency from `developmentOnly` to `testAndDevelopmentOnly`.
|
|
With the default scope of `developmentOnly`, the `bootTestRun` task will not pick up changes in your code, as the devtools are not active.
|