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.
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 theWireMock
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()
, andtrace()
methods of theWireMock
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.
- 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 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 replacenull
with the a newMappingBuilder
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 thecom.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.
In the 6th example, Is it okay if we use urlMatching() instead of urlPathMatching()
If no then explain the reason
The difference between the
urlMatching()
andurlPathMatching()
methods is that theurlMatching()
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.