Are you tired of writing tests which have a lot of boilerplate code? If so, get started with Spock Framework >>

WireMock Tutorial: Request Matching, Part Three

This blog post describes how we can specify expectations for the JSON document that is received by our WireMock server. After we have finished this blog post, we:

  • Can compare the actual JSON document with the expected JSON document.
  • Understand how we can ensure that an attribute is found from the JSON document.
  • Know how we can compare the actual attribute value with the expected attribute value.
  • Can ensure that the size of an attribute is equal to the expected value.
  • Understand how we can specify expectations for sub-documents.

Let’s begin.

Getting Started

As we remember, before we can specify our expectations for the JSON document received by our WireMock server, we have to specify the expected request method and request URL. After we have done this, we can specify our other expectations by using a MappingBuilder object.

For example, if we expect that our WireMock server receives a POST request to the URL: ‘/api/message’, we can create the required MappingBuilder object by using the following code:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should compare the actual URL path with the expected URL path")
    void shouldCompareActualUrlWithExpectedUrlRegex() {
        givenThat(post(urlEqualTo("/api/message"))
                //Specify the other expectations here
                .willReturn(aResponse().withStatus(200))
        );

        String serverUrl = buildApiMethodUrl();
        ResponseEntity<String> response = restTemplate.getForEntity(serverUrl,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }


    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

When we want to specify our expectations for the received JSON document, we have to follow these steps:

  1. Invoke the withRequestBody() method of the MappingBuilder interface.
  2. Specify our expectations by creating a new ContentPattern object and pass the created object to the withRequestBody() method as a method parameter.

We can create the required ContentPattern object by using the static factory methods of the WireMock class. When we specify our expectations for the content of the received JSON document, we can use these three methods:

  • The equalToJson() method ensures that the actual JSON document is equal to the JSON document given as a method parameter.
  • The matchingJsonPath(String value) method ensures that the actual JSON document matches with the JsonPath expression given as a method parameter.
  • The matchingJsonPath(String value, StringValuePattern valuePattern) method ensures that the value fetched by using a JsonPath expression is equal to the expected value that is specified by using a StringValuePattern object.
The previous part of my WireMock tutorial introduces several factory methods that help you to create new StringValuePattern objects.

Next, we will take a look at some examples which demonstrate how we can use these methods when we specify our expectations for the JSON document received by our WireMock server.

Comparing the Actual JSON Document With the Expected JSON Document

If we want to ensure that the actual JSON document is equal to the expected JSON document, we have to specify our expectation by using the equalToJson() method of the WireMock class. By default, this method doesn’t ignore array order and additional attributes. This means that:

  • If the actual JSON document contains an attribute that is not found from the expected JSON document, our expectation is not met.
  • If the actual JSON document contains an array that is found from the expected JSON document, both arrays must use the same order or our expectation is not met.

Let’s take a look at three examples which demonstrate how this method works.

Example 1: Specifying the Expected JSON Document

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"message": "Hello World!"
}

If we expect that our WireMock server receives this JSON document, we must specify our expectation by passing the expected JSON document to the equalToJson() method as a method parameter.

After we have specified our expectation, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should compare the actual json with the expected json")
    void shouldCompareActualRequestBodyWithExpectedRequestBody() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(equalToJson("{\"message\": \"Hello World!\"}"))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"message\": \"Hello World!\"}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Example 2: Ignoring Additional Attributes

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"name": "Petri Kainulainen",
	"message": "Hello World!"
}

If we expect that our WireMock server receives a JSON document that doesn’t have the name attribute, we have to disable the additional attribute check when we invoke the equalToJson() method of the WireMock class.

After we have specified our expectation, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should compare the actual json with the expected json")
    void shouldCompareActualRequestBodyWithExpectedRequestBody() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(equalToJson("{\"message\": \"Hello World!\"}", 
                        false, 
                        true
                ))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"name\": \"Petri Kainulainen\", \"message\": \"Hello World!\"}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Example 3: Ignoring Array Order

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"messages": ["foobar", "Hello World!"]
}

If we expect that our WireMock server receives a JSON document which has the messages array that is sorted in a different way, we have to disable the array order check when we invoke the equalToJson() method of the WireMock class.

After we have specified our expectation, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should compare the actual json with the expected json")
    void shouldCompareActualRequestBodyWithExpectedRequestBody() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(equalToJson(
                        "{\"messages\": [\"Hello World!\", \"foobar\"]}",
                        true,
                        false
                ))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"messages\": [\"foobar\", \"Hello World!\"]}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Let’s move on and find out how we can ensure that an attribute is found from the JSON document received by our WireMock server.

Verifying That an Attribute Is Found From the Received JSON Document

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"message": "Hello World!"
}

If we expect that the received JSON document has the message attribute, we have to specify our expectation by using the matchingJsonPath() method of the WireMock class. When we invoke this method, we have to create a JsonPath expression which returns the value of the expected attribute and pass this expression to the matchingJsonPath() method as a method parameter.

After we have specified our expectation, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should ensure that the actual request body contains an attribute")
    void shouldEnsureThatActualRequestBodyContainsAttribute() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(matchingJsonPath("$.message"))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"message\": \"Hello World!\"}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Next, we will find out how we can compare the actual attribute value with the expected attribute value.

Comparing the Actual Attribute Value With the Expected Attribute Value

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"message": "Hello World!"
}

If we want to ensure that the value of the message attribute is: ‘Hello World!’, we have to specify our expectation by using the matchingJsonPath() method of the WireMock class. We can specify the expected value by using one of these two options:

First, we can create a JsonPath expression that specifies the expected value and pass this expression to the matchingJsonPath() method as a method parameter. After we have specified our expectation, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should ensure that the given attribute has the expected value")
    void shouldEnsureThatActualRequestBodyHasAttributeWithExpectedValue() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(matchingJsonPath(
                        "$.[?(@.message == 'Hello World!')]")
                )
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"message\": \"Hello World!\"}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Second, we can combine a JsonPath expression with a matcher. If we want to use this technique, we have to provide two method parameters to the matchingJsonPath() method:

  1. A JsonPath expression that returns the actual value of the attribute.
  2. A StringValuePattern object that specifies the expected value.

After we have specified our expectation by using this technique, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should ensure that the given attribute has the expected value")
    void shouldEnsureThatActualRequestBodyHasAttributeWithExpectedValue() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(matchingJsonPath("$.message", 
                        equalTo("Hello World!")
                ))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"message\": \"Hello World!\"}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Let’s move on and find out how we can ensure that the size of an attribute is correct.

Ensuring That the Size of an Attribute Is Correct

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"messages": ["Hello World!"]
}

If we expect that the messages attribute has only one message, we have to specify our expectation by using the matchingJsonPath() method of the WireMock class. When we invoke this method, we have to create a JsonPath expression which specifies the expected size of the messages attribute and pass this expression to the matchingJsonPath() method as a method parameter.

After we have specified our expectation by using this technique, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should ensure that the attribute has the expected size")
    void shouldEnsureThatActualRequestBodyHasAttributeWithExpectedValue() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(matchingJsonPath("$[?(@.messages.size() == 1)]"))
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>(
                "{\"messages\": [\"Hello World!\"]}"
        );

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}

Next, we will find out how we can specify expectations for sub-documents.

Specifying Expectations for Sub-Documents

Let’s assume that the system under test sends the following JSON document to our WireMock server:

{
	"message": {
		"name": "Petri Kainulainen",
		"text": "Hello World"
	}
}

If we want to ensure that the message attribute contains the correct sub-document, we can specify our expectation by using the matchingJsonPath() method of the WireMock class. When we invoke this method, we have to pass two method parameters to the invoked method:

  1. A JsonPath expression that returns the actual value of the attribute.
  2. A StringValuePattern object that specifies the expected sub-document. Because we want to specify the expected sub-document by using the JSON format, we have to create the required StringValuePattern object by using the equalToJson() method of the WireMock class. When we invoke this method, we have to pass the expected sub-document to the invoked method as a method parameter.

After we have specified our expectation by using this technique, the source code of our test class looks as follows:

import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static org.assertj.core.api.Assertions.assertThat;

class RequestMatchingTest {

    private RestTemplate restTemplate;
    private WireMockServer wireMockServer;

    @Test
    @DisplayName("Should ensure that the json has the expected sub-document")
    void shouldEnsureThatActualRequestBodyHasAttributeWithExpectedSubDocument() {
        givenThat(post(urlEqualTo("/api/message"))
                .withRequestBody(matchingJsonPath("$.message",
                        equalToJson("{" +
                                "\"name\": \"Petri\", " +
                                "\"text\": \"Hello World!\"" +
                        "}"))
                )
                .willReturn(aResponse().withStatus(200))
        );

        String apiMethodUrl = buildApiMethodUrl();
        HttpEntity<String> httpRequest = new HttpEntity<>("" +
                "{\"message\": " +
                    "{\"name\": \"Petri\", \"text\": \"Hello World!\"}" +
                "}");

        ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl,
                HttpMethod.POST,
                httpRequest,
                String.class
        );
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    private String buildApiMethodUrl() {
        return String.format("http://localhost:%d/api/message",
                this.wireMockServer.port()
        );
    }
}
When you specify your expectation for a sub-document, you can naturally use other factory methods which return StringValuePattern objects.

We can now specify expectations for the JSON documents received by our WireMock server. Let’s summarize what we learned from this blog post.

Summary

This blog post has taught us six things:

  • When we want to specify our expectations for the body of the received HTTP request, we have to invoke the withRequestBody() method of the MappingBuilder interface.
  • When we want to specify our expectations for the received JSON document, we have to create a new ContentPattern object and pass this object to the withRequestBody() method as a method parameter.
  • We can create the required ContentPattern object by using the static factory methods of the WireMock class.
  • The equalToJson() method of the WireMock class allows us to compare the actual JSON document with the expected JSON document.
  • The matchingJsonPath() method of the WireMock class allows us to specify our expectations by using JsonPath expressions.
  • The matchingJsonPath() method of the WireMock class allows us to combine JsonPath expressions with matchers (StringValuePattern objects).

P.S. You can get the example application of this blog post from Github.

0 comments… add one

Leave a Comment