WireMock Tutorial: Request Matching, Part One

This blog post provides an introduction to the request matching support of WireMock. After we have finished this blog post, we:

  • Understand how request matching works.
  • Know how we can compare the actual HTTP request method with the expected request method.
  • Can compare the actual request URL with the expected request URL.

Let's start by taking a quick look at request matching.

A Very Quick Introduction to Request Matching

Request matching allows us to specify expectations for the HTTP requests which are received by our WireMock server. We can use request matching for two purposes:

  • We can configure our WireMock server to return a specific HTTP response when it receives an HTTP request that fulfills our expectations.
  • We can ensure that our WireMock server receives an HTTP request that fulfills our expectations.

WireMock has a versatile support for specifying expectations for the different attributes of an HTTP request. For example, we can specify expectations for HTTP request methods, request URLs, cookies, request headers, request parameters, and request bodies.

When we specify expectations for the attributes of an HTTP request, we have to use the static factory methods of the com.github.tomakehurst.wiremock.client.WireMock class.

Next, we will find out how we can specify expectations for HTTP request methods and request URLs.

Specifying Expectations for Request Methods and Request URLs

Before we can specify expectations for the other attributes of an HTTP request, we have to specify the expected request method and request URL by following these steps:

First, we have to specify the expected request method by using one of the following methods:

  • The static any() method of the WireMock class ignores the request method. In other words, we should use this method when we don't care about the request method of the expected HTTP request.
  • The static delete(), get(), options(), post(), put(), and trace() methods of the WireMock class allow us to specify the expected request method.

These methods take a UrlPattern object as a method parameter and return a MappingBuilder object. The UrlPattern class allows us to specify the expected request URL, and the MappingBuilder interface declares the methods that allow us to specify other expectations for the expected HTTP request.

Second, we have create a new UrlPattern object and pass this object to the method that specifies the expected request method. When we want to specify the expected request URL, we can use these static methods of the WireMock class:

  • The anyUrl() method ignores the request URL. In other words, we should use this method when we don't care about the URL of the expected HTTP request.
  • The urlEqualTo() method compares the actual URL with the expected URL given as a method parameter. When we specify the expected URL, we have to use the full URL that contains the query and fragment components.
  • The urlMatching() method matches the actual URL with a regex given as a method parameter. When we create the URL regex, we must ensure that our regex matches with the full URL that contains the query and fragment components.
  • The urlPathEqualTo() method compares the actual URL path with the expected URL path given as a method parameter.
  • The urlPathMatching() method matches the actual URL path with a regex given as a method parameter.
I want to point out two things:

  • When we specify the expected URL, we have to omit the URL components that precede the path component. In other words, if the full URL is: 'http://localhost:8080/foo?id=2', we can specify the expected URL by using the string: '/foo?id=2'. Also, if we want to use a regex, our regex must match with the string: '/foo?id=2'.
  • If the expected HTTP request has multiple request parameters, we should use path based matching because it allows us to specify our expectations in a way that doesn't depend on the order of the expected request parameters. We will talk more about this in the next part of my WireMock tutorial.

Next, we will take a look at six examples which demonstrate how we can specify expectations for the HTTP request method and request URL. However, before we can do that, we have to take a quick at our test class.

Our test class has one test method which ensures that our WireMock server returns the HTTP status code 200 when it receives an HTTP request that fulfills our expectations. We can stub HTTP requests by using the static givenThat() method of the WireMock class. This method takes a MappingBuilder object as a method parameter and returns a StubMapping object.

After we have implemented this test method, 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.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 return the HTTP status code 200")
    void shouldReturnHttpStatusCodeOk() {
        givenThat(null
                .willReturn(aResponse().withStatus(200))
        );

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


    private String buildApiMethodUrl(Long messageId) {
        return String.format("http://localhost:%d/api/message?id=%d",
                this.wireMockServer.port(),
                messageId
        );
    }
}
I want to point out three things:

  • 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.
  • This post doesn't describe how we can stub HTTP requests with WireMock. I will explain this in an upcoming part of my WireMock tutorial. However, if you don't understand how our test method works, you should take a look at the user's manual of WireMock.
  • Our test method cannot pass because we didn't create the MappingBuilder object that specifies our expectations for the HTTP request received by our WireMock server. The next examples will replace null with the a new MappingBuilder object.

Let's begin.

Example 1:

If we expect that our WireMock server receives an HTTP request that can use any request method and request URL, we have to specify our expectations by using the any() and anyUrl() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 ignore the request method and URL")
    void shouldIgnoreRequestMethod() {
        givenThat(any(anyUrl()).willReturn(aResponse()
                .withStatus(200))
        );

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

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

Example 2:

If we expect that our WireMock server receives a GET request to any request URL, we have to specify our expectations by using the get() and anyUrl() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 request method with the expected method")
    void shouldCompareActualRequestMethodWithExpectedRequestMethod() {
        givenThat(get(anyUrl()).willReturn(aResponse()
                .withStatus(200))
        );

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

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

Example 3:

If we expect that our WireMock server receives a GET request to the URL: '/api/message?id=1', we have to specify our expectations by using the get() and urlEqualTo() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 with the exact expected URL")
    void shouldCompareActualUrlWithExactExpectedUrl() {
        givenThat(get(urlEqualTo("/api/message?id=1")).willReturn(aResponse()
                .withStatus(200))
        );

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

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

Example 4:

If we expect that our WireMock server receives a GET request to a URL that starts with the string: '/api/' and ends with the string: '?id=1', we have to specify our expectations by using the get() and urlMatching() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 with the expected URL regex")
    void shouldCompareActualUrlWithExpectedUrlRegex() {
        givenThat(get(urlMatching("/api/([a-z]*)\\?id=1"))
                .willReturn(aResponse().withStatus(200))
        );

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

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

Example 5:

If we expect that our WireMock server receives a GET request to the URL path: '/api/message', we have to specify our expectations by using the get() and urlPathEqualTo() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 shouldCompareActualUrlWithExactExpectedUrl() {
        givenThat(get(urlPathEqualTo("/api/message"))
                .willReturn(aResponse().withStatus(200))
        );

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


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

Example 6:

If we expect that our WireMock server receives a GET request to a URL path that starts with the string: '/api/', we have to specify our expectations by using the get() and urlPathMatching() methods of the WireMock class.

After we have created the required MappingBuilder object, 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.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 path regex")
    void shouldCompareActualUrlWithExpectedUrlRegex() {
        givenThat(get(urlPathMatching("/api/([a-z]*)"))
                .willReturn(aResponse().withStatus(200))
        );

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


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

We can now specify our expectations for the request method and request URL of an HTTP request that is received by our WireMock server. Let's summarize what we learned from this blog post.

Summary

This blog post has taught us six things:

  • Request matching allows us to specify expectations for the HTTP requests which are received by our WireMock server.
  • We can use request matching when we are stubbing and/or mocking HTTP requests.
  • We can specify expectations for HTTP request methods, request URLs, cookies, request headers, request parameters, and request bodies.
  • When we specify expectations for the attributes of an HTTP request, we have to use the static factory methods of the com.github.tomakehurst.wiremock.client.WireMock class.
  • When we specify the expected URL, we have to omit the URL components that precede the path component.
  • If the expected HTTP request has multiple request parameters, we should use path based matching because it allows us to specify our expectations in a way that doesn’t depend on the order of the expected request parameters.

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

3 comments… add one
  • fakef Oct 6, 2019 @ 21:20

    In the 6th example, Is it okay if we use urlMatching() instead of urlPathMatching()
    If no then explain the reason

    • Petri Oct 6, 2019 @ 21:44

      The difference between the urlMatching() and urlPathMatching() methods is that the urlMatching() method matches the provided regex against the full URL of the HTTP request (the URL doesn't include host and protocol though). This means that you must use a regex which doesn't "break" if the actual HTTP request has query parameters.

      Also, you might want to take a look at the WireMock User's Manual because it has some nice examples which demonstrate how you can use these methods.

Leave a Reply