This blog post describes how we can specify expectations for the XML document that is received by our WireMock server. After we have finished this blog post, we:
- Can compare the actual XML document with the expected XML document.
- Understand how we can ensure that an element is found from the XML document.
- Know how we can compare the actual element value with the expected element value.
- Can ensure that the received document contains X elements.
- Understand how we can specify expectations for sub-documents.
- Know how we can deal with XML namespaces.
Let's begin.
Getting Started
As we remember, before we can specify our expectations for the XML 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 XML 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 XML document, we can use these three methods:
- The
equalToXml(String value)
method ensures that the actual XML document is equal to the XML document given as a method parameter. - The
matchingXPath(String value)
method ensures that the actual XML document matches with the XPath expression given as a method parameter. - The
matchingXPath(String value, StringValuePattern valuePattern)
method ensures that the value fetched by using an XPath 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 XML document received by our WireMock server.
Comparing the Actual XML Document With the Expected XML Document
If we want to ensure that the actual XML document is equal to the expected XML document, we have to specify our expectation by using the equalToXml()
method of the WireMock
class. When we use this method, we have to know these three things:
- This method takes the expected XML document as a method parameter.
- By default, this method ignores the order of XML attributes but doesn't ignore the order of XML elements. In other words, if we use this method, the elements of the expected XML document must be in the same order as the elements of the actual XML document.
- Because WireMock uses XMLUnit, we can configure the XML comparison settings by using the
static
setXXX()
methods of theXMLUnit
class.
Next, we will take a look at one example which demonstrates how this method works. Let's assume that the system under test sends the following XML document to our WireMock server:
<message>Hello World!</message>
If we expect that our WireMock server receives this XML document, we must specify our expectation by passing the expected XML document to the equalToXml()
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should compare the actual xml with the expected xml") void shouldCompareActualRequestBodyWithExpectedRequestBody() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(equalToXml("<message>Hello World!</message>")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>( "<message>Hello World!</message>" ); 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 element is found from the XML document received by our WireMock server.
Verifying That an Element Is Found From the Received XML Document
Let's assume that the system under test sends the following XML document to our WireMock server:
<message>Hello World!</message>
If we expect that the received XML document has the message
element, we have to specify our expectation by using the matchingXPath()
method of the WireMock
class. When we invoke this method, we have to create an XPath expression that identifies the expected element and pass this expression to the matchingXPath()
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should ensure that the actual request body contains an element") void shouldEnsureThatActualRequestBodyContainsElement() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath("/message")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>( "<message>Hello World!</message>" ); 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 element value with the expected element value.
Comparing the Actual Element Value With the Expected Element Value
Let's assume that the system under test sends the following XML document to our WireMock server:
<message>Hello World!</message>
If we want to ensure that the value of the message
element is: 'Hello World!', we have to specify our expectation by using the matchingXPath()
method of the WireMock
class. We can specify the expected value by using one of these two options:
First, we can create an XPath expression that specifies the expected value and pass this expression to the matchingXPath()
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should ensure that the given element has the expected value") void shouldEnsureThatActualRequestBodyHasElementWithExpectedValue() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath("/message[text()='Hello World!']")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>( "<message>Hello World!</message>" ); 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 an XPath expression with a matcher. If we want to use this technique, we have to provide two method parameters to the matchingXPath()
method:
- An XPath expression that returns the actual value of the element.
- 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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should ensure that the given element has the expected value") void shouldEnsureThatActualRequestBodyHasElementWithExpectedValue() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath("/message/text()", equalTo("Hello World!") )) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>( "<message>Hello World!</message>" ); 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 XML document contains X elements.
Ensuring That the XML Document Contains X Elements
Let's assume that the system under test sends the following XML document to our WireMock server:
<messages> <message>Hello World!</message> </messages>
If we expect that the received XML document has only one message
element, we have to specify our expectation by using the matchingXPath()
method of the WireMock
class. When we invoke this method, we have to create an XPath expression which specifies the expected number of the message
elements and pass this expression to the matchingXPath()
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should ensure that the document has X elements") void shouldEnsureThatActualRequestBodyHasXElements() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath("/messages[count(message)=1]")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>("<messages>" + "<message>Hello World!</message>" + "</messages>" ); 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 XML document to our WireMock server:
<message> <name>Petri</name> <text>Hello World!</text> </message>
If we want to ensure that the name
element contains the correct sub-document, we can specify our expectation by using the matchingXPath()
method of the WireMock
class. When we invoke this method, we have to pass two method parameters to the invoked method:
- An XPath expression that returns the actual value of the element.
- A
StringValuePattern
object that specifies the expected sub-document. Because we want to specify the expected sub-document by using the XML format, we have to create the requiredStringValuePattern
object by using theequalToXml()
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should ensure that the XML has the expected sub-document") void shouldEnsureThatActualRequestBodyHasElementWithExpectedSubDocument() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath("/message/name", equalToXml("<name>Petri</name>") )) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>("<message>" + "<name>Petri</name>" + "<text>Hello World!</text>" + "</message>" ); 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 deal with XML namespaces.
Dealing With XML Namespaces
Let's assume that the system under test sends the following XML document to our WireMock server:
<sample:message xmlns:sample="http://www.example.com">Hello World!</sample:message>
If we want to specify expectations for an XML document that uses namespaces, we have to declare the used namespaces by using the withXPathNamespace()
method of the MatchesXPathPattern
class. This method takes two method parameters:
- The name of the XML namespace.
- The URI of the XML namespace.
For example, if we want to ensure that the sample:message
element contains the text: 'Hello World!', we have to specify our expectation by following these steps:
- Create an XPath expression that specifies the expected value of the
sample:message
element. - Declare the
sample
namespace by invoking thewithXPathNamespace()
method of theMatchesXPathPattern
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; @DisplayName("Specify expectations for an XML document") class RequestMatchingTest { private RestTemplate restTemplate; private WireMockServer wireMockServer; @Test @DisplayName("Should compare the actual XML with the expected XML") void shouldCompareActualRequestBodyWithExpectedRequestBody() { givenThat(post(urlEqualTo("/api/message")) .withRequestBody(matchingXPath( "/sample:message[text()='Hello World!']" ) .withXPathNamespace("sample", "http://www.example.com") ) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(); HttpEntity<String> httpRequest = new HttpEntity<>( "<sample:message xmlns:sample=\"http://www.example.com\">" + "Hello World!" + "</sample:message>"); 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() ); } }
withXPathNamespace()
method multiple times.
We can now specify expectations for the XML documents received by our WireMock server. Let's summarize what we learned from this blog post.
Summary
This blog post has taught us seven 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 XML 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 the static factory methods of theWireMock
class. - The
equalToXml()
method of theWireMock
class allows us to compare the actual XML document with the expected XML document. - The
matchingXPath()
method of theWireMock
class allows us to specify our expectations by using XPath expressions. - The
matchingXPath()
method of theWireMock
class allows us to combine XPath expressions with matchers (StringValuePattern
objects). - If we want to specify expectations for an XML document that uses namespaces, we have to declare the used namespaces by using the
withXPathNamespace()
method of theMatchesXPathPattern
class.
P.S. You can get the example application of this blog post from Github.