This project is a POC to combine Micronaut's Test Resources project with Spring Boot. The project is still in very early stage and subject to bigger changes.
TestContainers is a great framework for testing your application code against infrastructure components like databases, message brokers and so forth. If you are developing Spring Boot applications, the PlayTika TestContainers library is a helpful assistent to connect your Spring Application context with the TestContainers.
Micronaut released a sub-project called Test Resources which also comes with TestContainers under the hood but it provides a test resources server which takes care of provisioning your containers during the build. This server can run standalone and can therefore survive independent builds and keep your containers alive. This in turn can significantly reduce your build times.
This library combines those two approaches by implementing instances of TestResourcesResolver, mapping
to the default properties of Spring Boot, i.e. spring.datasource.url
. A special PropertySource
fetches the properties
from the resource server.
That way, together with the build plugins from Micronaut for Gradle and Maven, you can easily test your Spring Boot applications using Micronaut Test Resources and TestContainers and benefit from keeping your containers alive during builds.
This library consists of two parts:
- a thin client layer to be packaged with your Spring Boot application (for test cases) which configures your ApplicationContext
- plugins for the test resources server for the various modules (MariaDB, MinIO) which configure the containers based on Spring Boot properties
Follow the following steps, to get it running:
First thing is to add the Gradle Plugin to your build. If you use Maven, please consult the official documentation.
Go to your build.gradle.kts
:
plugins {
id("io.micronaut.test-resources") version "3.7.7"
}
In multi-module projects ensure that the plugin is applied on every module (especially on the one which is holding your Spring Boot application tests).
Then, add this to your gradle.properties
:
micronautVersion=3.8.7
Next thing is to go to the module which contains your Spring Boot application
and your @SpringBootTest
and add the module springboot-testresources-client
to the test-scope in your build.gradle.kts
:
dependencies {
testRuntimeOnly("io.cloudflight.testresources.springboot:springboot-testresources-client:0.0.2")
}
We strongly recommend to use testRuntimeOnly
instead of testImplementation
in order to avoid having Micronaut
on your implementation classpath.
Then, as a last step, you need to add one or more of our test modules to the testResourcesImplementation
scope, which
has been created by the Micronaut Test Resources plugin.
Suppose you need a container for MariaDB, then add the following line:
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-jdbc-mariadb:0.0.2")
}
That's it. You can now run your @SpringBootTest
.
To give you an even better overview, here is a full example of a minimalistic Spring Boot application with Spring Data + MariaDB.
build.gradle.kts
plugins {
id("io.cloudflight.autoconfigure-gradle") version "0.9.4"
id("io.micronaut.test-resources") version "3.7.7"
}
version = "0.1"
group = "io.cloudflight"
repositories {
mavenCentral()
}
autoConfigure {
java {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa:3.0.1")
runtimeOnly("org.jetbrains.kotlin:kotlin-reflect")
testImplementation("org.springframework.boot:spring-boot-starter-test:3.0.1")
runtimeOnly("org.mariadb.jdbc:mariadb-java-client:3.0.6")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
testRuntimeOnly("io.cloudflight.testresources.springboot:springboot-testresources-client:0.0.2")
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-jdbc-mariadb:0.0.2")
}
Then, create a src/main/kotlin/io/cloudflight/Application.kt
package io.cloudflight
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.Id
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.JpaRepository
@SpringBootApplication
class Application
fun main(vararg args: String) {
runApplication<Application>(args)
}
@Entity
class Person(var name: String) {
@Id
@GeneratedValue
var id: Long = 0
}
interface PersonRepository : JpaRepository<Person, Long>
Configure the application to create a database on startup with Hibernate Auto-DDL in src/main/resources/application.yaml
:
spring:
jpa:
hibernate:
ddl-auto: create-drop
And finally, create a src/test/kotlin/io/cloudflight/ApplicationTest.kt
:
package io.cloudflight
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
class ApplicationTest(
@Autowired private val repository: PersonRepository
) {
@Test
fun enterData() {
repository.save(Person(name = "Klaus"))
}
}
If you now run the test, the following happens:
- The Micronaut Test Resources starts the test resources server which can handle requests to configure a MariaDB docker container
- The
ApplicationTest
picks up the TestResourcesEnvironmentPostProcessor which uses the TestResourcesPropertySource to automatically configure properties likespring.datasource.url
orspring.datasource.username
based on the settings from the docker container. - The MariaDbTestResourcesProvider starts the
MariaDBContainer
from the TestContainers project - The
ApplicationTest
connects itsPersonRepository
to exactly that database and can insert data to the DB.
As you see, we did not have to configure properties like spring.datasource.url
manually, that was all provided automatically.
Spring Boot Test Resources is compatible with Spring Boot 3.x but also with 2.7. It requires a JDK 17 (we could also easily publish it for JDK 11 or below, but we want you to push towards the latest LTS)
Additionally, you need a plugin to start the test resources server. We have tested our library with the Micronaut Test Resources Gradle Plugin, but it should also work fine for Maven.
We currently only provide some few modules, as this library is still in a PoC phase, but the number of modules will grow over time.
For each module you can override the default image which is being pulled by adding
test-resources:
containers:
mariadb:
image-name: mariadb:10.3
You can also always override any of the provided properties by adding any of those properties below test-resources.containers.mariadb
. For example,
if you want to use another username
than the default one, you can add:
test-resources:
containers:
mariadb:
image-name: mariadb:10.3
username: myusername
This will create a MariaDB container based on mariadb:10.3
with the default username myusername
.
- Module-ID: mariadb
- Default-Image: mariadb
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-jdbc-mariadb:0.2.1")
}
- Provided properties:
spring.datasource.url
spring.datasource.username
spring.datasource.password
spring.datasource.driver-class-name
Make sure to add the following property to your application-test.yml
to accept the MSSQL Server License Agreement:
test-resources:
containers:
mssql:
accept-license: true
- Module-ID: mssql
- Default-Image: mcr.microsoft.com/mssql/server:2019-CU16-GDR1-ubuntu-20.04
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-jdbc-mssql:0.2.1")
}
- Provided properties:
spring.datasource.url
spring.datasource.username
spring.datasource.password
spring.datasource.driver-class-name
- Module-ID: postgres
- Default-Image: postgres
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-jdbc-postgres:0.2.1")
}
- Provided properties:
spring.datasource.url
spring.datasource.username
spring.datasource.password
spring.datasource.driver-class-name
- Module-ID: minio
- Default-Image: minio/minio
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-minio:0.2.1")
}
- Provided properties:
minio.url
minio.access-key
minio.secret-key
minio.region
- Module-ID: rabbitmq
- Default-Image: rabbitmq
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-rabbitmq:0.2.1")
}
- Provided properties:
spring.rabbitmq.host
spring.rabbitmq.port
spring.rabbitmq.username
spring.rabbitmq.password
- Module-ID: redis
- Default-Image: redis
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-redis:0.2.1")
}
- Provided properties:
spring.data.redis.url
- Module-ID: azurite
- Default-Image: mcr.microsoft.com/azure-storage/azurite
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-azurite:0.2.1")
}
- Provided properties:
spring.cloud.azure.storage.blob.account-name
spring.cloud.azure.storage.blob.account-key
spring.cloud.azure.storage.blob.endpoint
- Module-ID: mailhog
- Default-Image: mailhog/mailhog
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-mailhog:0.2.1")
}
- Provided properties:
spring.mail.host
spring.mail.port
test-resources.mailhog.api-url
- Module-ID: elasticsearch
- Default-Image: docker.elastic.co/elasticsearch/elasticsearch
dependencies {
testResourcesImplementation ("io.cloudflight.testresources.springboot:springboot-testresources-elasticsearch:0.2.1")
}
- Provided properties:
spring.elasticsearch.uris
spring.elasticsearch.password