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() ); } }
@BeforeEach
and @AfterEach
methods from the code examples of this blog post because they add no value to this blog post. If you don't know how you can configure WireMock, you should read this blog post.When we want to specify our expectations for the received JSON document, we have to follow these steps:
- Invoke the
withRequestBody()
method of theMappingBuilder
interface. - Specify our expectations by creating a new
ContentPattern
object and pass the created object to thewithRequestBody()
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 aStringValuePattern
object.
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:
- A JsonPath expression that returns the actual value of the attribute.
- 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:
- A JsonPath expression that returns the actual value of the attribute.
- 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 requiredStringValuePattern
object by using theequalToJson()
method of theWireMock
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() ); } }
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 theMappingBuilder
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 thewithRequestBody()
method as a method parameter. - We can create the required
ContentPattern
object by using thestatic
factory methods of theWireMock
class. - The
equalToJson()
method of theWireMock
class allows us to compare the actual JSON document with the expected JSON document. - The
matchingJsonPath()
method of theWireMock
class allows us to specify our expectations by using JsonPath expressions. - The
matchingJsonPath()
method of theWireMock
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.