WireMock Tutorial: Request Matching, Part Four

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()
        );
    }
}
I removed the @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:

  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 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 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 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 the XMLUnit 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:

  1. An XPath expression that returns the actual value of the element.
  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;

@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:

  1. An XPath expression that returns the actual value of the element.
  2. 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 required StringValuePattern object by using the equalToXml() 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;

@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:

  1. The name of the XML namespace.
  2. 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:

  1. Create an XPath expression that specifies the expected value of the sample:message element.
  2. Declare the sample namespace by invoking the withXPathNamespace() method of the MatchesXPathPattern 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()
        );
    }
}
If our XML document uses multiple namespaces, we have to invoke the 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 the MappingBuilder 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 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 equalToXml() method of the WireMock class allows us to compare the actual XML document with the expected XML document.
  • The matchingXPath() method of the WireMock class allows us to specify our expectations by using XPath expressions.
  • The matchingXPath() method of the WireMock 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 the MatchesXPathPattern class.

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

1 comment… add one

Leave a Reply