When an application depends on a third party API, you always seem to face similar challenges. Do you integrate against it, even in development? What about the tests, won’t they be flaky if need it to be present for them to run?

Meanwhile, if you decide to use stubs, how sure are you that the application is, well, working? I can’t remember how many times I have had perfectly green tests based on mocks that were not testing anything, because the API had changed in some way.

Recently I’ve been thinking about this, and I have tried to address this through API recordings.
I know this idea from the Ruby world, concretely VCR. This time, however, I wanted to use it in a Java project, so I looked at WireMock.

Why?

Following the Testing Pyramid, we want to have most of our tests at the lowest possible level. Unit tests should not be doing network requests. On the other hand, if we use mocks, they should be close to the source, ideally based on actual requests.

If we have these mocks already, why not use them for our local development? I want my app to boot app and quickly show something, agian without the need to connect to the outside.

And, I want automation. Editing .json files by hand is a recipe for errors and outdated data. I want to avoid friction.

Thanks to WireMock, this process is very convenient and almost transparent to the app. A bit of plumbing is required, but it is real easy to do.

Development

For the development server, we rely on certain mocks being present, that we will serve transparently by starting a WireMock server on startup. To do that in a Spring Boot project, we use this initializer:

It is important to set mock.active to false for any non-development environment. Other than that, we configuration points to the local server instead of the real API:

serverUrl: http://localhost:${mock.port}mock:active:trueport:8080

Unit tests

The unit tests that need to use this mock data will use the same mocks from WireMock that the development server uses. Activating the mocks is as easy as inheriting from the RecordedTest class, which looks like this:

Inheritance and @Before and @After annotations is perhaps not a best practice, but it makes the tests really succint. Defining additional behavior is easy by just defining extra WireMock rules. This way you can test more specific scenarios like timeouts while keeping most of the regular code quite clean.

Integration tests

This is where everything comes together. Our integration tests make sure that the connection to the real API works. In the process, the interactions get recorded so that we can store that as the mocks that the rest of the app uses. To enable a test to become a RecordingTest, you need to inherit the class:

After that the new recordings are present and ready to be used. This can be done manually or integrated into a pipeline, to make sure that it happens often.

NOTE: If the Third Party API is secured through mTLS, you can still make this setup work by making WireMock aware of the keystore that your code uses to connect to it, by creating a custom config for the WireMock server:

Summary

The setup contains a bit of magic, but the result is quite simple to use. This way, you can achieve a great testing coverage without compromising the development experience, all while keeping your core unit tests slim and fast. If you have fought with out-of-sync mocks before, you will see the advantage!