Database Integration Testing with Testcontainers

Kwo Ding
  • Kwo Ding
  • 1 May 2023


For database integration testing an in-memory database like H2 is commonly used. However, this does not guarantee that your application actually works properly with the production database, which is not an in-memory database. The H2 database has many limitations as listed here and more importantly the limitations on the compatbility modes described here. This means that for example a simple DDL script on a real database will not always work on H2 in a compatibility mode.

So an in-memory database has its limitations, but how can we test the integration with a real database? Well, either connect to an actual database which is production-like, or use Testcontainers which we will focus on here. This enables to test the application under test with an actual database locally by basically spinning up a Docker container for the database on-the-fly.

Let’s set it up, using MySQL as an example.

First, add the necessary dependencies to the project.


Configure your application to connect to the MySQL container from Testcontainers. In a Spring Boot application it looks like this:

    url: jdbc:tc:mysql:///test

Finally, use the database container in your test as follows.

private final ContactClient client = new ContactClient();

private final Faker faker = Faker.instance();

private final MySQLContainer<?> mysql = new MySQLContainer<>();

void startContainer() {

void shouldCreateContactWithRealDatabase() {
    long contactId = faker.random().nextLong();
    Contact contact = Contact.newBuilder()


    Contact actualContact = client.getContact(contactId);


Note: this test is based on the Client-Test Model.

The database container will be spun up before the test and shut down after it.

A few built-in features from Testcontainers that are noteworthy:

  • You can set a specific Docker image and tag in the constructor of MySQLContainer (similarly for any other database).
  • To create tables with a DDL script when creating the database container, it can be specified like this: new MySQLContainer<>().withInitScript("init.ddl").
  • It is possible to keep the container alive by utilizing the “reuse” feature from Testcontainers so that you can analyze the actual database state after the test. Create a file on the classpath with testcontainers.reuse.enable=true as contents.


Testcontainers can be used to test the integration of your application with a real database without relying on a full-blown testing environment. This makes it easy to test this integration locally and on CI pipelines.

© 2023 Testing Boss. All rights reserved.