Mock your APIs for fast, robust & comprehensive testing with WireMock

Arvind Kumar
5 min readSep 6, 2020

In this new world of software development where everything is being distributed and going in micro mode, I mean microservices mode we all developers know the pain of doing unit/integration testing.

Certain challenges I would like to point out —

  1. Mocking the 3rd party APIs
  2. Interacting with the microservice which is still in development
  3. Parallel development of microservices poses many challenges because we have to wait for the completion of development dependent service to confirm the right integration
  4. Reliable mocking
  5. Not able to create a production-like environment for testing
  6. Even if interact with 3rd party service, there are a certain failure or timeout scenarios which are difficult to get

WireMock solves many such challenges very easily and quickly, let’s see what’s this all about

WireMock is a simulator for HTTP-based APIs.

It enables you to stay productive when an API you depend on

  1. doesn’t exist or
  2. isn’t complete.

It supports the testing of edge cases and failure modes that the real API won’t reliably produce. And because it’s fast it can reduce your build time from hours down to minutes.

Before starting the journey with WireMock, let’s compare it with Mockito which is another popular java mocking library

Let’s see one by one how we can do the testing with WireMock and Spring Boot

We are taking dummy service for the example, below is the diagram to show the different components of it, If you want to get the source code of this jump to GitHub

WireMock can help us in 2 ways

  1. Wiremock as a JVM library
  2. WireMock as a standalone server

There are 2 core factors in testing the API

  1. Stubbing part
  2. Verification of the interaction with mock library

Let’s see how we can use both (I’ll use Gradle as a build tool which is just to add the dependency, you are very much free to use Maven or another build tool) —

Wiremock as a JVM library

To add this into your project add this dependency

testCompile "com.github.tomakehurst:wiremock-jre8:2.27.0"

We have to do the three steps here —

  1. Wiremock configuration
  2. Stubbing
  3. Verification

First, let’s configure the WireMock

@BeforeEach
void setup() {
wireMockServer = new WireMockServer();
configureFor("localhost", 8080);
wireMockServer.start();
}

then next comes the stubbing part —

  1. Stubbing for any URL and 200(OK) response
stubFor(any((anyUrl())).willReturn(ok()));

2. Stubbing for specific URL and specific response

stubFor(post(urlPathEqualTo("/payments"))
.withRequestBody(equalToJson("{\n" +
"\"cardNumber\" : \"1111-1111-1111-1111\",\n" +
"\"cardExpiryDate\" : \"2020-08-03\",\n" +
"\"amount\" : 200.0\n" +
"}"))
.willReturn(okJson("{\n" +
"\"paymentId\" : \"3333\",\n" +
"\"paymentResponseStatus\" : \"SUCCESS\"\n" +
"}")));

3. If we have more than one interaction in the same method under test then we can do more than one stubbing as well

//given
stubFor
(post(urlPathEqualTo("/payments"))
.withRequestBody(equalToJson("{\n" +
"\"cardNumber\" : \"1111-1111-1111-1111\",\n" +
"\"cardExpiryDate\" : \"2020-08-03\",\n" +
"\"amount\" : 200.0\n" +
"}"))
.willReturn(okJson("{\n" +
"\"paymentId\" : \"3333\",\n" +
"\"paymentResponseStatus\" : \"SUCCESS\"\n" +
"}")));

stubFor(get(urlPathEqualTo("/fraudCheck/1111-1111-1111-1111"))
.willReturn(okJson("{" +
" \"blacklisted\": \"false\"" +
"}")));

4. When we have multiple stubbing and we have to prioritize it then do it as follows

stubFor(get(urlPathEqualTo("/fraudCheck/1234-1234-1234-1234"))
.atPriority(1)
.willReturn(okJson("{" +
" \"blacklisted\": \"false\"" +
"}")));

stubFor(get(urlPathEqualTo("/fraudCheck/1234-1234-1234-1234"))
.atPriority(2)
.willReturn(okJson("{" +
" \"blacklisted\": \"true\"" +
"}")));

5. If the request input is non-deterministic then

// Given
stubFor
(post(urlPathEqualTo("/payments"))
.withRequestBody(
matchingJsonPath("cardNumber")
)
.withRequestBody(
matchingJsonPath("cardExpiryDate")
)
.withRequestBody(
matchingJsonPath("amount")
)
.willReturn(okJson("{" +
" \"paymentResponseStatus\": \"SUCCESS\"" +
"}")));

6. Simulating delay in response

//given
stubFor
(post(urlPathEqualTo("/payments"))
.withRequestBody(equalToJson("{\n" +
"\"cardNumber\" : \"1111-1111-1111-1111\",\n" +
"\"cardExpiryDate\" : \"2020-08-03\",\n" +
"\"amount\" : 200.0\n" +
"}"))
.willReturn(okJson("{\n" +
"\"paymentId\" : \"3333\",\n" +
"\"paymentResponseStatus\" : \"SUCCESS\"\n" +
"}").withFixedDelay(1100)));

7. Simulating the Error response

//this is the 1st way
stubFor
(post(urlPathEqualTo("/payments")).willReturn(serverError()));
//this is the 2nd way
stubFor
(post(urlPathEqualTo("/payments")).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK)));
//this is the 3rd way
stubFor
(post(urlPathEqualTo("/payments")).willReturn(aResponse().withFault(Fault.RANDOM_DATA_THEN_CLOSE)));

Finally, let’s do the verification part —

WireMock keeps track of all the interactions that happened with it which we can verify to ascertain that whatever we stubbed for is used properly while executing the test.

this is very easy and quick to do

// this is for POST requestverify(postRequestedFor(urlPathEqualTo("/payments")).withRequestBody(
equalToJson("{\n" +
"\"cardNumber\" : \"1111-1111-1111-1111\",\n" +
"\"cardExpiryDate\" : \"2020-08-03\",\n" +
"\"amount\" : 200.0\n" +
"}")
));
//this is for GET request
verify
(getRequestedFor(urlPathEqualTo("/fraudCheck/1111-1111-1111-1111")));

That’s all about the stubbing and verification part

Now let’s understand the use of WireMock as a standalone server

To add this in the classpath —

testCompile group: 'com.github.tomakehurst', name: 'wiremock-standalone', version: '2.27.0'

By adding this we can start the WireMock server effectively by recording the request and response which makes stubbing very easy and quick

Now let’s start with the Configuration part

This step is pretty much the same as earlier —

@BeforeEach
void setup() {
wireMockServer = new WireMockServer();
wireMockServer.start();

wireMockServer.startRecording("http://localhost:8082");

}
@AfterEach
void tearDown() {
wireMockServer.stopRecording();
wireMockServer.stop();
}

startRecording(“actual-api-url”) call is important and we expect the actual URL of 3rd party. This is a one-time activity only.

When we have the above steps and execute the test which calls the 3rd party we get the mapping of request-response in the JSON/XML(whatever applicable) form at the location (src>test>resources>mappings). mappings folder has to be created manually and then all the request-response interaction with 3rd party gets recorded

the content of mapping looks something like this

{
"id" : "2782e17d-eda8-4dfd-a7b9-2b8012a35362",
"name" : "payments",
"request" : {
"url" : "/payments",
"method" : "POST",
"bodyPatterns" : [ {
"equalToJson" : "{\"cardNumber\":\"1111-1111-1111-1111\",\"cardExpiryDate\":\"2020-08-03\",\"amount\":200.0}",
"ignoreArrayOrder" : true,
"ignoreExtraElements" : true
} ]
},
"response" : {
"status" : 200,
"body" : "{\"paymentId\":\"99868a1f-b15a-4906-bb4f-b944152693da\",\"paymentResponseStatus\":\"SUCCESS\"}",
"headers" : {
"Content-Type" : "application/json",
"Date" : "Sun, 16 Aug 2020 09:49:57 GMT",
"Keep-Alive" : "timeout=60"
}
},
"uuid" : "2782e17d-eda8-4dfd-a7b9-2b8012a35362",
"persistent" : true,
"insertionIndex" : 1
}

After we have got the mappings then we can remove the recordings part from the configuration and going forward these mapping files will be used

@BeforeEach
void setup() {
wireMockServer = new WireMockServer();
wireMockServer.start();

// wireMockServer.startRecording("http://localhost:8082");

}
@AfterEach
void tearDown() {
// wireMockServer.stopRecording();
wireMockServer.stop();
}

This way we got the stubbing part

The verification part is the same as the above.

That’s all about this post.

Now you can see how easy and quick to test the APIs with WireMock and apart from this it’s also more like the real-time interaction with API which makes it more better choice as a mocking library/server. If you wish to get the complete guide and running code, I have created the complete course on youtube channel GreenLearner, check out the playlist here. All the source code are uploaded on GitHub

See you next time :)

Stay Safe | Take Care

@@ Happy Coding|Learning|Sharing @@

--

--