API Mocking with WireMock

Testing delivers an abundance of new learning opportunities to software developers. By taking responsibility for the test coverage of our own code, we learn how to write good tests, and improve our coding styles to ease the testing process. I was quick to understand this in my most recent project, where we pursued test-driven development to improve and expand on existing code.

In order to write good tests, we need to know the right tools for the job at hand. Looking to write tests for a few database operations? No bother, Mockito has your back. Trying to handle asynchronous calls in your tests? Look no further than Awaitility. Tempted to mock a couple of API requests? Sure, but how? This is where WireMock comes into play.

Source: wiremock.org

WireMock proved exceptionally useful for testing POST requests in our code. After writing a couple of end-to-end tests with WireMock, I found myself growing to really appreciate this tool. So why not share this newly acquired knowledge?

It’s festival time here in Edinburgh, offering a huge range of shows, bars, and food stalls to complement an already fantastic city. With that in mind, I’m going to demonstrate how WireMock works within a small Java application I’ve written to use the Edinburgh Festival Listings API.

Background

Before implementing WireMock into our testing, it would be worth providing a general overview of the API and the Java application we’re working with. The API consists of two endpoints:

  1. https://api.edinburghfestivalcity.com/events, and

2. https://api.edinburghfestivalcity.com/events/{UUID},

where UUID is the unique identifier for a festival event. We’ll be calling the first endpoint in our application with a GET request, which we expect to return all events for the current year.

In order to successfully receive these events, we require two keys to authorise our request: an API key, and a secret signing key. Registration is required to obtain these keys, which are unique to each account holder and should not be shared.

Once obtained, we’ll use these keys to form a query to our endpoint when we call it. Following the API documentation, we begin with query /events?key=X for API key X. We sign this query using the HMAC-SHA1 algorithm, making sure it encodes in plain ASCII hex. The result, signature Y, is appended to our query to give us /events?key=X&signature=Y. This, appended to our endpoint address, authorises our requests to the Festival API endpoint.

Our endpoint for making the request will be Java class FestivalEndpoint. This class includes a getEvents() method, which will generate the URI for the API call, create a HTTP request using the URI, and execute this request to retrieve the events.

There’s two additional classes to this application: APIKeyDetailsFileParser and APIUrlGenerator. The former parses plain-text file api_key_details.txt, which contains my API and secret signing keys. The latter generates the URI for the API request given these two keys.

There’s also an Environment enumerator, which consists of “Local” and “Prod”. This will later prove significant when we’re testing our code: the environment we use determines whether we send a request to the real Festival API endpoint or a test endpoint.

To wrap that up, the overall structure is as follows:

We’ll introduce test coverage for FestivalEndpoint in FestivalEndpointTest. This class will contain one test called testGetAllEvents, which calls the getAllEvents() method in FestivalEndpoint. WireMock will mock the Festival API within this test. Let’s begin with the following template:

Configuration

The Java application is setup with Maven and JUnit. Before we proceed to write our test, we’ll need to inject the WireMock dependency into our project POM file:

Once Maven’s rebuilt the project with its new dependency, we’ll need to define a WireMockRule to our test class which will set up and tear down a WireMock server for each test we run within the class:

By default, WireMockRule configures a server on localhost using port 80. We may wish to amend this rule to use a different port, or dynamically select a port each time we execute a test. For our class, we’ll configure WireMock to dynamically select a HTTPS port. This is supported with WireMock options passed into the WireMockRule constructor, like so:

There we have it: a WireMock server on localhost with a HTTPS port. Pretty sweet, right? Whilst there’s plenty of additional options available to us — HTTPS certificates, proxy settings, and Jetty configurations — this rule as it stands will suffice for our class. WireMock’s official documentation describes other options in greater detail.

Stubbing the Request

With WireMockRule implemented into our class, we’re ready to begin writing testGetAllEvents(). We’ll instantiate FestivalEndpoint in the setUp method, passing in a “Local” environment from our Environment enumerator like so:

We want testGetAllEvents() to call getAllEvents() in FestivalEndpoint. However, we don’t want our requests to go to the real festival API when we’re running our test. How do we configure the application to send requests to the WireMock server, and how does this server recognise when a good request is received? Furthermore, how does the server know how to respond to such requests?

The environment passed into the FestivalEndpoint constructor answers the first question. When “Prod” is passed into the constructor, our class sends requests to host api.edinburghfestivalcity.com, otherwise requests are sent to localhost. Since WireMockRule sets up a server on localhost, passing in a “Local” environment does the trick!

To answer the remaining two questions, we require a WireMock stub. The WireMock server will be set up on localhost with a predetermined port from WireMockRule, so all we need for our stub is the URL’s path, and any queries or fragments it contains.

Let’s start with a basic stub for a GET request, which looks for requests sent to “/some/thing” and returns an empty response:

We need to replace “/some/thing” with the URI path we expect to call in getAllEvents(). This doesn’t include ports or hosts, since this is already configured through WireMockRule. Following from our earlier discussion on the API, the path we intend to use is /events?key=X&signature=Y for API key X and signature Y.

This path presents a problem to us. Suppose we’re sharing our test with work colleagues, or the readership of a blog. Then how can we configure WireMock to match a path containing keys and signatures when we’re not supposed to be sharing these details?

urlEqualTo would allow everyone with access to this test to copy our keys! An alternative approach is required. WireMock’s urlMatching comes to the rescue here, allowing us to define a regular expression (regex) which will match our URI, irrespective of which keys we use.

The API key is an alphabetic 15-digit sequence, whilst the secret signing key is an alphanumeric 40-digit sequence. With regex, these patterns can be defined by [A-Za-z]{15} and [0-9A-Za-z]{40}, respectively. Escaping ? with backslashes since it holds a special meaning for regex, we have our stub URI:

With a pattern provided, our next step is to identify whether or not our request requires a header. On this occasion, the answer’s yes! The Festival API outlines a requirement for an Accept header which specifies response format application/json;ver=2.0. This is achieved like so:

Now with our GET request outlined, we need to define the response to send back! We expect three properties in our response: a status code, a header, and a body.

We’re testing the happy path on this occasion, where a successful status would be returned from the API. Therefore the status code is 200. The response header will correspond to our Accept header in the request: “Content-Type” with value application/json;ver=2.0. The body will be example JSON of the form [{\"title\":\"Test Event\"}]. We include these details in aResponse() like so:

Incorporating this response into our earlier work, we have our complete stub:

Verifying the Request

Now we’re ready to execute testGetAllEvents()! WireMock will listen for our test request to the Festival API, and return response 200 with the header and body provided. Or will it? How do we verify that call was actually made when we run testGetAllEvents()? We may well have defined a stub for a request we never make!

This is where WireMock’s verify method features prove useful. This method takes two parameters: The number of times we expect our request to be received (optional), and a request definition similar in form to the definition provided in our stub. We expect the WireMock server to receive exactly one request matching what’s defined in our stub, which is expressed using the same urlMatching pattern and Accept header as before:

With both a stub and a verify defined for our test, we’re ready to execute! All that remains is to assert that our response body is [{\"title\":\"Test Event\"}]. We’ll leave that in the capable hands of JUnit’s assertEquals — WireMock’s done it’s part!

Conclusion

That wraps up our WireMock example! Having defined a stub, and implemented verification for our call, we have a fully written test case to guarantee our code would make a good request to the Festival API — assuming our keys to be valid!

Proof of a passing test! (IntelliJ)

WireMock supports a wide range of additional features for API mocking. We’ve only demonstrated a GET request on this API — WireMock is equally capable of supporting POST requests. Furthermore, WireMock can be configured to support a whole host of scenarios as we discussed at the end of our configuration step. The official documentation serves as an excellent point of reference for further detail.

If you fancy seeing the Festival application in full, it’s available for viewing on GitLab. You’re more than welcome to clone the repository and try it out for yourself. You will need to register for your own Festival API key details in order to do so. Once you have your keys, you can create api_key_details.txt in src/main/resources and paste these into your file. Make sure to follow the format defined in api_key_details_template.txt, with the arrow brackets removed. That’s all from me — enjoy!

Like what you read? Give Ross Rhodes a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.