How We Started Integration Testing Our Backend Services
By: Lars Gröber
Tags: Testing, How To, Software Development, Backend, Integration Testing

Writing good tests is hard but more so is setting up tooling to write tests efficiently. In this article, I will share how we set up Integration tests using flapdoodle’s embedded MongoDB, Kotlin, and Spring Boot. At Inheaden, testing was always a high priority for us. While unit test coverage was always high, we had not invested a lot of time into proper Integration tests. With an increasing load on our servers and additional client projects, we needed to change this to keep operation at high quality.

First up, why even bother with Integration tests? While writing unit tests, especially a lot of good ones, helps to make sure that new code works and does not break the old one, Integration tests are important to test software as a whole. One simply cannot assume that because every part of an application works, the combination of all of them will work as well. So adding good Integration tests to an application will increase your confidence in it to work as expected.

Setup

Here, I expect you to be familiar with setting up and running a Spring Boot application using Kotlin. So I will not go into this. What we do need is to install the embedded MongoDB, spring-boot-starter-test and JUnit 5 (using Maven):

This will install the necessary dependency to use an embedded MongoDB when testing your application.

The application

Now we will look at testing a microservice designed to send mail (fittingly called “EMailService”). It, of course, sends mails but also keeps track of every mail sent using a MongoDB. Building an integration test for an application like this poses two challenges:

Mocking (but also verifying) the behavior of external services — in this case, the SMTP server.

Mocking the database while staying as close to the real one as possible.

Using the tools we installed we can solve both of these.

Application Code

You might note that this is still Java Code. While adding Integration tests into our code base we are also looking into moving to Kotlin. New services and new test code is written in Kotlin only. I will publish our approach to this soon.

Our service exposes (for simplicity) only one API method to the internet: POST /send/email

We model this using a spring boot RestController.

Its one method uses Formdata because we also offer to add attachments using other methods. It then combines all parameters into one request object and passes this to a Service which will handle the actual business logic.

The sendMail method then creates the MimeMessage, adds the email log to the database, and sends the message. Here we see that it also needs the user to be authenticated and to be allowed to send mails.

Anatomy of an Integration test

The @SpringBootTest annotation starts up an application context for your spring boot app using a random port. We configure MockMvc using the next annotation and set a custom *.properties file using the last one. Our IntegrationTestBase autowires a MongoTemplate and the MockMvc. It also calls mongoTemplate.db.drop() after each test.

Where is the embedded MongoDB you might ask? Since we added its dependencies early using test scope it will start automatically when running the tests. It will download the latest version of MongoDB and pick up the database port automatically.

The actual test uses Mockito to mock the mailSender, here a proxy around JavaMailSender. The test runs using a mock user with the correct authorities and tests if a mail would have been send and if the email log has been created.

Conclusion

Since starting our journey for better test coverage using Integration tests, we could set up a lot of tests for different scenarios. Running these tests on our CI system reliably without the need to set up real databases saved us from a lot of hassle. We hope this article helps you in setting up your own Integration tests.