Stateful tests in Wiremock
A common scenario in many software projects is integration with external services. We integrate with data or authorization providers. We integrate using REST calls or gRPC or many other technologies.
When you want to test the integration of your application with an external service with which you communicate using HTTP, Wiremock can come as a handy tool. It provides a mechanism for recording and playback interaction with other API. The feature I would like to present you in this post is something I have recently discovered — support of stateful behaviour. In a few words —it allows you to emulate different responses based on previous interactions with Wiremock.
Example scenario
Let’s consider the following scenario: we want to retrieve a bunch of invoices from external service, but before we can do that we need to authorize our application. After successful authorization, we are able to properly download invoices data.
In terms of interactions, we want to emulate that any unauthorized call to /invoices
endpoint with GET
method will return 403 HTTP
status code. When we send GET
request to /auth
we authorize the application and unlock /invoices
endpoint. From now on we can send a request to /invoices
endpoint and get 200 HTTP
status code as a response. The flow diagram below shows the test scenario:
We can handle the above with aforementioned stateful behaviour feature. In this case, Wiremock acts as a state machine. In the beginning, it is in the Started
state. After sending a request to /auth
endpoint Wiremock changes its state to Authorized
and properly handles requests to /invoices
endpoint.
How to do it?
Basics
How can we tell Wiremock to act as in the example scenario? There are two ways to do it: by fluent Wiremock API or by JSON definition. Here, we will use the JSON definition. If you want to check fluent API you can visit http://wiremock.org/docs/stubbing/ ).
Wiremock requires that JSON should have at least request and response fields. The response field defines response (duh…) which will be sent to the client after receiving a matching request. So, for instance, the following JSON will return 200 HTTP status code
in response to any GET
request to /example
endpoint:
Unauthorized responses
Now we can proceed to our test scenario. First of all, we have to define a scenario in which the test will be executed. To quote the documentation: WireMock supports state via the notion of scenarios. A scenario is essentially a state machine whose states can be arbitrarily assigned. In the JSON definition, we introduce a new field scenarioName
and set "Test scenario"
as its value. The field acts like an identifier for a given test case. Additionally, there is a requiredScenarioState
key which lets Wiremock apply given stub depending on at which state Wiremock is. We assigned Started
value here because Wiremock always starts scenarios in Scenario.STARTED state. The first part of the example test case (unauthorized responses) can be defined using the following JSON:
Authorize
The second step of the example test case (authorizing an application) requires changing Wiremock state to authorized when it receives a proper GET
request to the /auth
endpoint. We can achieve this by adding newScenarioState
to the stub. In the following example, it changes the current Wiremock state to Authorized
.
Authorized responses
Finally, after authorization, Wiremock can respond with a success to GET
/invoices
request. Stub definition below is very similar to the definition in the first step, except for the status code change, requiredScenarioState
value is different. The new value means that the Wiremock will apply the stub then and only then when it is in at Authorized
state otherwise this stub definition is ignored.
Check
Everything is set up, so now it’s the time to check if everything works properly. First of all, we have to set up a Wiremock server. I suggest using dockerized version of the server from https://github.com/rodolpheche/wiremock-docker . You can easily set up the server with just two commands:
Next, we have to send mappings to the Wiremock. All necessary mapping files (unauthorized_invoices.json, authorize.json, authorized_invoices.json
) are saved in the same directory in which curl
command is executed.
Everything is ready to go, so we can run requests for our test case:
Summary
Wiremock is a very powerful piece of software which lets you verify integrations with external HTTP services. It can save you a lot of time when implementing integration tests with external API calls. As you saw above, even complicated, stateful test scenarios can be easily done using the Stateful Behaviour feature.
Do you have any experience using Stateful Behaviour? Do you know any other cool feature of Wiremock? Let me know in the comments section below.