Integration testing in SpringBoot with TestContainers starter

Translation of the article was prepared on the eve of the start of the course “Spring Framework Developer”


One of the reasons why Spring and Spring Boot are so popular is their good support testing… Can be written as unit tests with Mockito without using the functionality of Spring, and integration with the initialization of the Spring context.

Integration tests may require interaction with external services such as relational databases, NoSQL databases, Kafka, and others. When testing, it is convenient to deploy these services in Docker containers.

Testcontainers

From Testcontainers documentation:

TestContainers is a Java library that supports JUnit tests by providing lightweight, temporary instances for popular databases, web browsers with Selenium, and anything else that can run in a Docker container.

With Testcontainers run Singleton Docker container as follows:

@SpringBootTest
@ContextConfiguration(initializers = {UserServiceIntegrationTest.Initializer.class})
class UserServiceIntegrationTest {
    private static PostgreSQLContainer sqlContainer;
    
    static {
        sqlContainer = new PostgreSQLContainer("postgres:10.7")
                .withDatabaseName("integration-tests-db")
                .withUsername("sa")
                .withPassword("sa");
        sqlContainer.start();
    }

    static class Initializer implements ApplicationContextInitializer {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
              "spring.datasource.url=" + sqlContainer.getJdbcUrl(),
              "spring.datasource.username=" + sqlContainer.getUsername(),
              "spring.datasource.password=" + sqlContainer.getPassword()
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }

    @Autowired
    private UserService userService;
    
    @Test
    void shouldGetAllUsers() {
        // test userService.getAllUsers()
    }   

}

Since this is used quite often, a starter was created by the community to simplify life – Testcontainers Spring Boot Starter

Testcontainers SpringBoot Starter

Testcontainers – starter depends on spring-cloud-starter… If your application does not use SpringCloud starters, then you need to add spring-cloud-starter as a test dependency.


    org.springframework.cloud
    spring-cloud-starter
    test

And also add the library for the database. For example, if you want to use Postgresql:


    com.playtika.testcontainers
    embedded-postgresql
    test

When adding embedded-postgresql the following properties will be available in the environment:

embedded.postgresql.port
embedded.postgresql.host
embedded.postgresql.schema
embedded.postgresql.user
embedded.postgresql.password

They can be used to set up a datasource.

Typically, Docker containers are only used for integration tests, not unit tests. With the help of profiles, we can disable them by default and enable them only for integration tests.

src/test/resources/bootstrap.properties

embedded.postgresql.enabled=false

src/test/resources/bootstrap-integration-test.properties

embedded.postgresql.enabled=true
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://${embedded.postgresql.host}:${embedded.postgresql.port}/${embedded.postgresql.schema}
spring.datasource.username=${embedded.postgresql.user}
spring.datasource.password=${embedded.postgresql.password}

Now you can run integration tests with a profile integration-test through @ActiveProfiles:

@SpringBootTest
@ActiveProfiles("integration-test")
class UserServiceIntegrationTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    void shouldGetAllUsers() {
        // test userService.getAllUsers()
    }   

}

You can specify a specific version of the docker image as follows:

src/test/resources/bootstrap-integration-test.properties

embedded.postgresql.dockerImage=postgres:10.7
embedded.postgresql.enabled=true

The Testcontainers starter already provides support for the most popular containers such as Postgresql, MariaDB, MongoDB, Redis, RabbitMQ, Kafka, Elasticsearch and others.
Surprisingly, there is currently no direct support for MySQL. Although there is a simple workaround for this as described here


Refactoring application code in Spring


Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *