Database integration tests

Did you ever get stuck while trying to find the best way to write a database integration test without mocking the third party? I know I did.

I’ve known about Martin Fowler since I was a junior developer. He is one of my favorite technology thought-leaders and I enjoy reading the thought-provoking articles that he publishes on his blog. In this post, I want to expand on his article about the test pyramid, in which he explains the difference between unit tests, integration tests and, UI tests. Specifically, I’ll expand on the part about integration tests.

I want to show you an easy way to run integration tests against a database. With this goal in mind, I’ve created a java demo project, that illustrates the idea and can be used as a starting point for more complicated applications.

I chose this topic because of all the moments of hesitation that I had when I was developing applications that interacted with a database. I wanted to have tests, but I didn’t want to spend too much time on their setup and my options were limited:

  • mocking/stubbing the database interaction layer
  • connecting to an in-memory database
  • connecting to a local/remote test database

Regardless of the option I picked, I always had the feeling that the solution could be more elegant. My hesitation would turn into frustration as the application grew and the tests would become harder to maintain. Recently, I discovered a better option: connecting the tests to a database running in a Docker container.

Database integration tests with docker

In my last project, Vlad and Max showed me that using docker containers simplifies running integration tests against a database. No mocking, no complicated infrastructure, no tinkering with configuration files. As long as you can run Docker on the build machine, you can run the tests.

This is the elegant solution that I was looking for:

  • install and configure Docker on the build servers and the developer machines that will run the tests
  • use docker-maven-plugin to build a docker image of the database and start/stop a container based on the image
  • populate the database with the necessary data (use ‘/docker-entrypoint-initdb.d/’ or a database migration tool like flyway)
  • finally, use maven-failsafe-plugin to run the integration tests

The benefits of Docker integration tests

Integration tests become portable and easy to debug. If the tests run on my laptop, they will run also on the build machine. If the tests fail on the build machine, the problem will also appear on my laptop.

Tests become repeatable: the plugin builds the docker image from scratch before the tests start and remove it after the tests finish.

This approach is transferable, to other types of integration tests. It’s easy to replace the database container with a dockerized REST API (in a move towards contract testing) or with a message queue container.

The demo project that I wrote is more than a typical “hello world” application. The integration test starts a docker MySQL container and makes a simple SQL query. You will notice that the docker-maven-plugin configuration is more complicated than necessary, given such a simple test. The reason: the code samples that I found online seemed trivial. I wanted to have a “bootstrap” project that I could reuse in real-life projects without the hassle of gluing everything from scratch.

This approach to writing integration tests has opened my eyes to the possibilities that exist today in the QA automation domain. The tooling around Docker seems varied enough to accommodate all test types. The number of plausible excuses for not having a proper CI pipeline is getting too low…