Mocking HTTP Services with WireMock – Part 1

By | March 2, 2018

I have been busy as of lately but feel that I really should squeeze in an article on mocking HTTP services after having found another nice tool that has been on my wishlist for some time.
In this first article I will show some examples of using WireMock that are of particular use to me. In the second part I will show how to use WireMock as a HTTPS mock service and REST Assured as a HTTPS client with and without mutual authentication.

The completed code of the example can be found on GitHub.

Setting Up an Example Project

As always, in my opinion, the best way to learn new things is to get down to the nitty-gritty with some code examples.
I’ll use Spring Boot for my example and a skeleton Maven project can be downloaded from Spring Initializr using this URL.
I am aware of the Spring Cloud Contract WireMock dependency that can be added when creating a Spring Boot project but I want this article to be applicable to other types of projects as well, so I have deliberately chosen to not to use it.

Add the following dependencies to the example project’s pom.xml file:

The first dependency is the WireMock dependency that contains all its dependencies in one JAR-file. This is the recommended dependency to use with SpringBoot projects and, as far as I understand, the easiest way to assure that all dependencies of WireMock are satisfied and that there will be no conflicts between the version of a dependency used by WireMock and another version of the same dependency used by your project or some other dependency of your project.

The next dependency is REST Assured, which I have already introduced.

Finally there is the JUnit 4 dependency. The Spring Boot parent pom-file include these JUnit dependency in its dependency-management section so no version number is needed.

Example Project Log Configuration

In the example project, I’ve used the following Logback configuration in a file named “logback-test.xml” located in src/test/resources:

Response Template

In one of the examples I show how WireMock can be configured to return responses created from templates. Create the template that later will be used in the example as follows.

  • Create the directory hierarchy __files/se/ivankrizsan/wiremocktest in the src/test/resources/ directory.
    Note that there are two underscore characters preceding “files”.
  • In the wiremocktest directory, create a file named “soap-response.xml” without quotes that has the following contents:

Note that the <ConversionRateResult> element contains a placeholder. Prior to returning the response, WireMock will replace the placeholder with the value of the HTTP header named “exchangerate” from the request .

Abstract Base-Class for Example Tests

In order to minimize repetition and have code that is easier to read, I’ve created the following abstract base-class for the tests:

Basic Use of WireMock

In this section some examples of how WireMock behaves in some basic cases:

  • Receiving an expected request.
  • Receiving a request that does not match the expected request.
  • Simulate long request processing time/slow response.
  • Creating responses from templates.

Before we start looking at the examples, create the class WireMockJUnit4Tests class containing the following code and constants:

Note that:

  • In the setup method, REST Assured is initialized for plain HTTP communication and a WireMock server is created and started programmatically.
    Being annotated with the JUnit 4 annotation @Before, this method will run once before each test in the class.
  • In the tearDown method, the WireMock server is stopped and any requests that the WireMock server received but was not expecting are logged.

Matching Request

The first example shows how to configure WireMock to expect a request with certain properties and what happens when WireMock receives a request that does match the expectations.

In the WireMockJUnit4Tests class create the following method:

Note that:

  • First in the method, the expected request is configured on the WireMock server.
    The properties that the expected request has are:
    The request is made to the /wiremocktest/hello path of the web application.
    An Accept HTTP header with the value text/plain.
  • The stubFor method is invoked on the WireMock server object.
    When creating a WireMock server programmatically, the stubFor method is to be invoked on the WireMock server object. When a JUnit Rule is used to create and start the WireMock server, the stubFor method is a static method.
  • As part of the configuration of the WireMock server, the response that is to be returned when having received a request matching the expectations is configured.
    The response will have the HTTP status 418, contain a HTTP header Content-Type with the value text/plain and have a response body containing the greeting “Hello client, this is the response body.”.
  • Next the REST Assured client sends a request and verifies the response.
  • The request that the REST Assured client sends has the following properties:
    Contains the HTTP header Content-Type with the value text/plain.
    Contains the HTTP header Accept with the value text/plain.
    Is to be sent to the /wiremocktest/hello path of the web application.
  • The REST Assured client expects a response with the following properties:
    HTTP status 418 and Content-Type text/plain.
  • After having sent the request and made the above verifications of the response, the HTTP status and headers of the response are logged to the console.
    This is just so that we have something to look at after having run the example.
  • Finally, the response body is verified to contain the word “Hello”.

If we now run the example/test, it should pass and you should see the following rows in the console output:

No surprises here – the test passed and everything is as expected.

Mismatching Request with Programmatically Created WireMock Server

Having had a look at a request that matched what WireMock was expected, we must of course investigate what happens when WireMock receives a request that does not match its expectations. This first mismatch-example shows the behaviour of WireMock when the WireMock server was created programmatically.
In the WireMockJUnit4Tests class create the following method:

Note that:

  • The WireMock server is configured to expect a request with the following properties:
    Request contains the Accept HTTP header with the value application/json.
    The request is made to the /wiremocktest/hello path of the web application.
  • When having received a matching request, WireMock is configured to return a response with the following properties:
    Content-Type text/plain. HTTP status 200 (OK). Response body “Hello World, we have a Houston!”.
  • Next a request is sent that does not match the expectations configured on WireMock.
    Note that no verification of the response is made with REST Assured.
  • The HTTP response status is verified to be 404 (not-found).
    This is the status that a programmatically created WireMock server will return when having received a request that does not match expectations.
  • The HTTP status and headers of the response are logged to the console.

If we run this example, it should also pass but the log in the console will indicate that there was a request that did not match expectations:

Note that:

  • The message that the request was not matched is logged twice.
    This is due to the fact that the message is returned in the body of the response too.
  • We can see that the cause of the mismatch was the value of the Accept HTTP header.
    It was expected to have the value application/json but contained text/plain.
  • The response HTTP status is 404.
    Again, this is the expected response HTTP status when a mismatching request is received.
  • Finally, we see that the code in the tearDown method logs the unmatched request and all of its details in even greater depth.

Mismatching Request with WireMock Server Created by JUnit Rule

As a contrast to the example above showing how a programmatically created WireMock server behaves when receiving a mismatching request, this example will show how a WireMock server created by a JUnit Rule behaves under the same circumstances.

The example is implemented in a separate class named WiremockJUnit4WithRuleTests that looks like this:

Note that:

  • There is a public instance variable named mWireMockRule of the type WireMockRule and annotated with the @Rule annotation.
    This is the JUnit rule that will setup and start the WireMock server before each test method and also stop it after each test method.
  • As in the previous example/test class there is a setup method that initializes REST Assured.
  • In the method mismatchingRequestTest the WireMock server is set up to expect a request with certain properties.
    Note that the stubFor method is invoked statically.
    When a JUnit Rule is used to create and start the WireMock server, the stubFor method is a static method. When creating a WireMock server programmatically, the stubFor method is to be invoked on the WireMock server object, as we have seen earlier.
  • A request is sent which have the Content-Type application/xml, as opposed to the expected content type text/plain.
  • An assertion is made that the HTTP response status is 404.
  • HTTP response status, headers and body are logged to the console.

If we run the test, it will fail and we will see the following in the console:

The main difference when compared to the previous example is that the test fails. In the console log, we see the HTTP response status, headers and body being logged so the test-failure is after the completion of the test method.
In IntelliJ IDEA, there is a clickable link in the console output that, if you click on it, shows a Comparison window detailing the differences between the request expected by the WireMock server and the actual request received. I recall having read that a similar feature is available in Eclipse.

Slow Responses

Another scenario that I frequently encounter when testing is simulating a slow service. As a spoiler, I will already now reveal that it is very easy to mock a slow HTTP service with WireMock. In addition, it is just as easy to verify that a request has taken a certain time with REST Assured.
Back in the WireMockJUnit4Tests class, implement the following method:

Note that:

  • The WireMock server is configured to expect a request with the following properties:
    Request contains the Accept HTTP header with the value text/plain.
    The request is made to the /wiremocktest/hello path of the web application.
  • When having received a matching request, WireMock is configured to return a response after a 10 second delay with the following properties:
    Content-Type text/plain. HTTP status 200 (OK). Response body “Hello client, this is the response body.”.
  • Using REST Assured, a request that matches what WireMock expects is sent.
  • REST Assured also verifies that the time it took to receive a response is longer that five seconds.

If we run the example/test, it will eventually pass. In IntelliJ IDEA the time consumed by a test method is displayed next to the method name in the Run view and there I can see that the test took approximately 11.5 seconds before completing.

Response Templates

I have written an article earlier about creating request and responses for testing purposes using Thymeleaf, so naturally I wanted to know if WireMock has support for creating responses from templates.
It turns out that WireMock indeed is able to create mock responses from templates. For this purpose it uses Handlebars as its templating engine. The following example from the WireMockJUnit4Tests class show how to return XML responses created from the template we prepared earlier.

Note that:

  • The WireMock server is stopped first in the test-method.
    This may seem odd but it is due to the fact that the WireMock server created in preparation for each test-method cannot be used in this test.
  • A response template transformer is created and its name is saved.
    This transformer is what enables response templating with WireMock.
    The boolean parameter supplied to the constructor indicated whether the transformer is to be applied automatically when creating all responses from the WireMock server. The reason for saving the name of the transformer is that we need to use the name to tell WireMock to use this particular transformer when creating responses later.
  • The WireMock server is created and started.
    Note the use of WireMockConfiguration to supply a more advanced configuration to WireMock and the use of the extensions method to supply the transformer created earlier.
  • The WireMock server is configured which request to expect.
    This is a request to the usual HTTP path with the Accept header having the value application/xml.
  • The WireMock server is configured which response to return when having received the expected request.
    Notice that the response body is to be read from a file, as specified by the withBodyFile method and that there is a call to a method named withTransformers taking the name of the response transformer we created earlier as a parameter.
    The astute reader concludes that no response transformer is necessary if you only want to serve responses with bodies created from statical file contents.
  • A request is sent to the service.
    The request is a request that WireMock expects and, in addition, there is a HTTP header named “exchangerate” that has the value 4.123.
    When we created the response template, this was the HTTP header value that is to be inserted into the XML fragment.
  • The response is verified.
    In addition to the type of verification we have seen earlier, the response is also verified to contain the value 4.123 at a location in the XML specified by an XPath expression.
  • Finally the response is logged to the console.

If we now run the test we’ll see this, among other things, in the console:

This concludes part one in the two-part series on WireMock. In the next part I will show testing with HTTPS; both with and without mutual authentication.
Until then, happy coding!

 

Leave a Reply

Your email address will not be published. Required fields are marked *