Integration Testing Spring Boot based Microservices using Spring REST Docs and WireMock

WireMock logo next to Spring Boot logo

There is no free lunch when it comes to embracing microservices, a wise person once said. While there are many advantages to the approach, it comes with some undeniable challenges. One of these challenges relates to achieving proper test coverage across your system. In this blog, I will explain how I was able to tackle this, in integration-testing my Spring Boot based REST API microservices using Spring REST Docs and WireMock.

Why Use WireMock?

In mocking microservices, I aim to keep their respective integration tests as lightweight as possible. Since it’s advisable to test in isolation, simply connecting to a staging instance of this service won’t cut it. If we test against a dataset that can change unpredictably, these tests are susceptible to unpredictable, confusing, and misleading failures.

Can we spin up a “real” system instance which remains isolated per-test? We could use a tool like Docker Compose to spin up a handful of containers which make up our stack of microservices, along with components like Redis, Kafka, MySQL, etc. But, in ensuring complete isolation between tests, this whole stack would have to be destroyed and rebuilt after each test execution. Resource requirements aside, this would make for an incredibly slow CI build. That is why I decided to embrace mocks.

How do I know my mocks will reflect actual system behavior?

We need a tool which verifies that our REST API endpoints are behaving as expected. That same tool should produce a mock REST API which mimics the behavior we just verified to be working. In this case, the tool I have wielded is a combination of these libraries:

  • Spring Boot
  • Spring MVC
  • Spring REST Docs
  • WireMock


First, let’s add a few things to your Gradle script:

Next, we need to modify our existing Spring MockMvc tests so that WireMock stubs are generated upon successful execution. Let’s add a few auto-configuration annotations to each test class:

This will only work if MockMvc itself has been auto-configured.

At this point, your MockMvc tests should look something like this:

Here, you are invoking a REST API call and ensuring that the proper response code is returned. Upon successful test execution, we want to expose the endpoint in our mock REST API for other projects to integration-test. You generally don’t want to associate a mock response with this exact request, byte-by-byte. Instead, you can add a few more lines of code to specify when the mock response should be returned, and verify that the original MockMvc request would match these conditions.

We are checking a few conditions here:

  1. The request URL matches the provided regex pattern.
  2. The value for JSON field “annotationIds”, as part of the request payload, matches the provided regex pattern.
  3. The JSON field “submittedAt”, simply, is present in the request payload.

Lets add one more line of code:

Through the magic of Spring, this will generate a WireMock stub called postTaskSubmissions.json, and an AsciiDoc which documents a example of the request. Documentation is critical; this will empower the rest of your team to use these generated mocks with ease.

You can define a Maven publication in your Gradle script; that will allow you to upload a mock JAR to a repository via gradle publish. I recommend using Gitlab for this. This will allow others to utilize these stubs without checking out the respective git repository. You can also run gradle publishToMavenLocal, in lieu of a remote repository configuration, for use in local integration testing.

You must run all of your MockMvc based tests to generate these stubs before attempting to publish the JAR.

You can run gradle asciidoctor to convert the aforementioned AsciiDoc into HTML. Here’s an example:

Next, let’s set up another Spring Boot project to utilize these mocks!

In your Gradle script, add a WireMock dependency, along with a dependency for the newly generated stubs. If your mock JAR is hosted on a remote repository, make sure you configure your repositories so that Gradle can find the jar.

Go to your integration test and add a class-level annotation:

Now, when we test, we want to invoke this mock REST API, not an actual instance. For example, instead of invoking a REST API hosted at, point to http://localhost:[an available port]. You can use the concept of profiles in Spring Boot to easily switch between base URLs per-environment.

That’s really it! In your integration test, when you make an HTTP request to this endpoint, WireMock will attempt to match the request. Remember, the request will have to match what we specified in the service’s MockMvc test, per method call .andDo(verify().... When a request is successfully matched, the response that’s returned is equivalent to what was returned while executing the respective MockMvc test. This exact response (JSON payload, status code, and headers) is detailed in the auto-generated AsciiDoc. If WireMock is unable to match the request, a 404 code will be returned. The response payload will provide additional information:

If your microservice ecosystem is purely Spring Boot based, then I do not have much else to offer; you are ready to integration test! However, if you work in a polyglot environment, you might be wondering how you could integration test in other languages like JavaScript or Python. We can do so with the help of Docker.

Bonus Section: Docker tutorial for polyglot integration testing

We will need to create a Dockerfile which contains a WireMock binary, along with the stubs that are generated after successful text execution:

This Dockerfile should not be placed in a root project directory. We are not trying to package the project itself into a Docker image. Instead, place it in a subdirectory such as mock-image-build/.

Next, we’ll need to copy our stubs into a directory that Docker will be able to find during the build process.

These commands are to be executed in a script or shell terminal, not within the newly created Dockerfile.

Next, let’s build the image, and push it to a registry:

You can perform these above steps manually, however, I would recommend that you automate this process in a CI/CD pipeline. For that, again, I recommend Gitlab.

Now, you can go ahead and spin up a container:

This will respond to HTTP calls just as we described in the earlier section. But you are no longer constrained to Spring Boot tests; you can invoke this mock API using any HTTP client written in any language.

In using a tool like Testcontainers, you can programmatically spin-up these lightweight containers in all sorts of integration test suites, whether they are written in Python, JavaScript, Go, etc. Note that WireMock is completely stateless; there is no need to reboot the container after each test to ensure isolation.

Happy testing!

LA based Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store