#HOWTO: Write Spring Boot integration tests with a ‘real’ database

Today I’ll show you a way to write integration tests for your Spring Boot based application with a ‘real’ database and not an embedded database like H2. In the last weeks, I was looking for a solution to write integration tests for my Spring Data based application which was using a Postgres database. I had the following requirements for this task:

  1. The integration tests should use the same database as in production (referring to the Twelve-Factor App I wanted to keep my environment during the tests as similar as possible to the production environment)
  2. The tests should not need any pre-setup before running (e.g. like manually setting up a test database)
  3. The tests should be able to be parallelized
  4. The tests should use my Flyway DDL scripts and create-drop (spring.jpa.hibernate.ddl-auto) shouldn’t be activated  for my tests
  5. Good integration with the excellent Spring tests environment

For this task, I found the awesome project: Testcontainers. The project describes itself as the following:

“Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.”

For using this dependency you need to have Docker on your local machine/on your build server (Jenkins etc.). With this project, you can use a @ClassRule or @Rule on each of your integration tests and define the Docker image for your test. For MySQL and Postgres and there are already built-in solutions but you are free to use the image of your choice like the following:

// generic container for self-defined Docker images
public static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(6379);

// built-in containers
public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer().withPassword("inmemory")

To meet my third requirement (The tests should be able to be parallelized) I configured the maven-surefire-plugin to run my test classes in parallel and every Postgres container will use a random port.


Overriding the properties for your application during the tests is as easy as the following snippet:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = IntegrationTest.Initializer.class)
public class IntegrationTest {

    public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer().withPassword("inmemory")

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues values = TestPropertyValues.of(
                    "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
                    "spring.datasource.password=" + postgreSQLContainer.getPassword(),
                    "spring.datasource.username=" + postgreSQLContainer.getUsername()

If you use the @SpringBootTest annotation to spin-up the whole Spring container and the embedded Tomcat your Flyway scripts will be executed against the container and you verify them as a side-effect. Adding the @Sql annotation to a test method you can execute further SQL scripts before your tests and add e.g. sample data before your test. These changes will get rolled back after your test method exists.

public void testRestEndpointForAllPersons() {

  ResponseEntity<Person[]> result = testRestTemplate.getForEntity("http://localhost:" + localPort +
      "/persons", Person[].class);

  assertThat(result.getBody().length, is(4));


For a full example with a sample Spring Boot application (simple CRUD REST application) visit my GitHub repository and have a look at the tests. I created three integration test classes (s (definitely not a best practice for your enterprise project) for creating, reading and deleting an entity to show you the parallel execution of the tests.

Happy integration-testing!

Leave a comment

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