Mock/Stub REST API with WireMock for better unit testing
The code shown in examples below is available in GitHub java-samples/wiremock repository.
WireMock
WireMock is a simulator for HTTP-based APIs. Some might consider it a service virtualization tool or a mock server. It enables you to stay productive when an API you depend on doesn't exist or isn't complete. It supports 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.When to use it
One case where WireMock is very helpful is when building a REST API client. Create simple REST API client using Jersey post describes a way to achieve this with Jersey. In most of the cases REST API might not be forced to fail with certain errors, so WireMock is an excellent addition to standard functional tests to verify that client is working correctly in corner cases. Also, it is mandatory for unit testing because it eliminates dependencies to external services. The mock server is extremely fast and under complete control. Another case where WireMock helps is if you need to create API tests, but API is not ready yet or not working. WireMock can be used to stub the service in order to make testing framework and structure. Once the real server is ready tests will just be elaborated and details cleared up.How to use it
WireMock is used in JUnit as a rule. More info on JUnit rules can be found in Use JUnit rules to debug failed API tests post. There are WireMockClassRule and WireMockRule. The most appropriate is the class rule, there is no need to create a mock server for each and every test, also additional logic is needed for port collision avoidance. In case you use other unit testing framework there is WireMockServer which can be started before tests and stopped afterward. The code given below is used to REST API client from Create simple REST API client using Jersey post. First JUnit class rule is created.public class JerseyPersonRestClientTest {
private static final int WIREMOCK_PORT = 9999;
@ClassRule
public static final WireMockClassRule WIREMOCK_RULE
= new WireMockClassRule(WIREMOCK_PORT);
private JerseyPersonRestClient clientUnderTest;
@Before
public void setUp() throws Exception {
clientUnderTest
= new JerseyPersonRestClient("http://localhost:" + WIREMOCK_PORT);
}
}
Port should be free, otherwise there is com.github.tomakehurst.wiremock.common.FatalStartupException: java.lang.RuntimeException: java.net.BindException: Address already in use: bind exception thrown.
Usage is very simple. There are several methods which are important. Method stubFor() is initializing the stub. Method get() notifies that stub is called with HTTP GET request. Method urlMatching() uses regular expression to match which API path is invoked, then willReturn() returns aResponse() withBody(). There are several with() methods which gives a variety of options for testing. Complete test is below:
@Test
public void testGet_WithBody_PersonJson() {
String personString = "{\"firstName\":\"FN1\",\"lastName\":\"LN1\"}";
stubFor(get(urlMatching(".*/person/get/.*"))
.willReturn(aResponse().withBody(personString)));
Person actual = clientUnderTest.get(1);
assertEquals("FN1", actual.getFirstName());
assertEquals("LN1", actual.getLastName());
}
This is the very straightforward case, where the client should work, but when you start to elaborate on with() scenarios you can sometimes catch an issue with the code being tested. See test below is working correctly in a case where API returns HTTP response code 500 - Internal Server Error. The client might need to add some verification on response codes as well:
@Test
public void testGet_WithStatus() {
String personString = "{\"firstName\":\"FN1\",\"lastName\":\"LN1\"}";
stubFor(get(GET_URL)
.willReturn(aResponse()
.withStatus(500)
.withBody(personString)));
Person actual = clientUnderTest.get(1);
assertEquals("FN1", actual.getFirstName());
assertEquals("LN1", actual.getLastName());
}