This blog post describes how we can use the request matching support of WireMock when we want specify expectations for cookies, HTTP headers, and request parameters. After we have finished this blog post, we:
- Can compare the actual cookie value with the expected cookie value.
- Know how we can compare the actual header value with the expected header value.
- Understand how we can compare the actual request parameter value with the expected request parameter value.
Let's begin.
Getting Started
As we remember, before we can specify our expectations for the other attributes of an HTTP request, 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 GET
request to the URL path: '/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(get(urlPathEqualTo("/api/message")) //Specify the other expectations here .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 ); } }
@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 cookies, HTTP headers, and request parameters, we have to use these methods provided by the MappingBuilder
interface:
- The
withCookie()
method allows us to compare the actual cookie value with the expected cookie value. - The
withHeader()
method allows us to compare the actual header value with the expected header value. - The
withQueryParam()
method allows to compare the actual request parameter value with the expected request parameter value.
These methods take two method parameters:
- The name of the cookie, header, or request parameter.
- A
StringValuePattern
object which specifies the expected value.
MappingBuilder
object. This means that we can specify our expectations by using a fluent API.We can create the required StringValuePattern
object by using the static
factory methods of the WireMock
class. When we specify the expected value of a cookie, a header, or a request parameter, we can use these five methods:
- The
equalTo()
method ensures that the actual value is equal to the string given as a method parameter. - The
equalToIgnoreCase()
method ignores case and ensures that the actual value is equal to the string given as a method parameter. - The
containing()
method ensures that the actual value contains the string given as a method parameter. - The
matching()
method ensures that the actual value matches with the regex given as a method parameter. - The
notMatching()
method ensures that the actual value doesn't match with the regex given as a method parameter.
Next, we will find out how we can specify expectations for cookies.
Specifying Expectations for Cookies
If we expect that the value of the name
cookie is equal to: 'Petri Kainulainen', we must specify our expectation by using the withCookie()
method of the MappingBuilder
interface.
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.*; 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 value with the expected value") void shouldCompareActualUrlWithExactExpectedUrl() { givenThat(get(urlEqualTo("/api/message?id=1")) .withCookie("name", equalTo("Petri Kainulainen")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(1L); HttpEntity<String> httpRequest = createHttpRequest(); ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl, HttpMethod.GET, httpRequest, String.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); } private HttpEntity<String> createHttpRequest() { HttpHeaders headers = new HttpHeaders(); headers.set("Cookie", "name=Petri Kainulainen"); return new HttpEntity<>(headers); } private String buildApiMethodUrl(Long messageId) { return String.format("http://localhost:%d/api/message?id=%d", this.wireMockServer.port(), messageId ); } }
CookieMatchingTest
class demonstrates how we can specify different expectations for cookie values.
Let's move on and find out how we can specify expectations for HTTP Headers.
Specifying Expectations for HTTP Headers
If we expect that the value of the Accept
header is equal to: 'application/json;charset=UTF-8', we must specify our expectation by using the withHeader()
method of the MappingBuilder
interface.
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.*; import org.springframework.web.client.RestTemplate; import java.util.Collections; 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 value with the exact expected value") void shouldCompareActualUrlWithExactExpectedUrl() { givenThat(get(urlEqualTo("/api/message?id=1")) .withHeader("Accept", equalTo(MediaType.APPLICATION_JSON_UTF8_VALUE)) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(1L); HttpEntity<String> httpRequest = createHttpRequest(); ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl, HttpMethod.GET, httpRequest, String.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); } private HttpEntity<String> createHttpRequest() { HttpHeaders headers = new HttpHeaders(); headers.setAccept( Collections.singletonList(MediaType.APPLICATION_JSON_UTF8) ); return new HttpEntity<>(headers); } private String buildApiMethodUrl(Long messageId) { return String.format("http://localhost:%d/api/message?id=%d", this.wireMockServer.port(), messageId ); } }
HeaderMatchingTest
class demonstrates how we can specify different expectations for header values.
If we are using basic authentication and we want to ensure that our WireMock server receives an HTTP request that has the correct username and password, we have specify the expected value of the Authorization
header.
However, because it is quite cumbersome to construct a correctly encoded header value, the MappingBuilder
interface declares a method that does the heavy lifting for us. This method is called withBasicAuth()
and it takes the expected username and password as method parameters.
After we have ensured that the Authentication
header contains the username: 'username' and password: 'password', the source code of our test class looks as follows:
import com.github.tomakehurst.wiremock.WireMockServer; import org.apache.commons.codec.binary.Base64; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.*; import org.springframework.web.client.RestTemplate; import java.nio.charset.Charset; 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 request has correct username and password") void shouldEnsureThatRequestHasCorrectUsernameAndPassword() { givenThat(get(urlEqualTo("/api/message?id=1")) .withBasicAuth("username", "password") .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl(1L); HttpEntity<String> httpRequest = createHttpRequest(); ResponseEntity<String> response = restTemplate.exchange(apiMethodUrl, HttpMethod.GET, httpRequest, String.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); } private HttpEntity<String> createHttpRequest() { HttpHeaders headers = new HttpHeaders(); String auth = "username:password"; byte[] encodedAuth = Base64.encodeBase64( auth.getBytes(Charset.forName("US-ASCII")) ); String authHeader = "Basic " + new String(encodedAuth); headers.set("Authorization", authHeader); return new HttpEntity<>(headers); } private String buildApiMethodUrl(Long messageId) { return String.format("http://localhost:%d/api/message?id=%d", this.wireMockServer.port(), messageId ); } }
BasicAuthMatchingTest
class demonstrates how we can specify the expected value of the Authentication
header.
Next, we will find out how we can specify expectations for request parameters.
Specifying Expectations for Request Parameters
If we expect that the value of the searchTerm
request parameter is equal to: 'foobar', we must specify our expectation by using the withQueryParam()
method of the MappingBuilder
interface.
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.*; 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 value with the expected value") void shouldCompareActualUrlWithExactExpectedUrl() { givenThat(get(urlPathEqualTo("/api/message")) .withQueryParam("searchTerm", equalTo("foobar")) .willReturn(aResponse().withStatus(200)) ); String apiMethodUrl = buildApiMethodUrl("foobar"); ResponseEntity<String> response = restTemplate.getForEntity(apiMethodUrl, String.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); } private String buildApiMethodUrl(String searchTerm) { return String.format("http://localhost:%d/api/message?searchTerm=%s", this.wireMockServer.port(), searchTerm ); } }
- If the expected HTTP request has multiple request parameters, we should use this approach because it makes our tests easier to read and write. Also, this technique allows us specify our expectations in a way that doesn’t depend on the order of the expected request parameters
- If we are specifying expectations for request parameters by using the
withQueryParam()
method, we should configure the expected URL by using path based matching because it doesn't make any sense to check the same expectation multiple times. - The
RequestParameterMatchingTest
class demonstrates how we can specify different expectations for request parameter values.
We can now specify our expectations for cookies, headers, and request parameters. Let's summarize what we learned from this blog post.
Summary
This lesson has taught us five things:
- Before we can specify our expectations for the other attributes of an HTTP request, we have to specify the expected request method and request URL.
- When we want to specify our expectations for cookies, HTTP headers, and request parameters, can use the methods declared by the
MappingBuilder
interface. - We can specify our expectations by using a fluent API.
- We can create a new
StringValuePattern
object, which specifies the expected value, by using thestatic
factory methods of theWireMock
class. - If we are specifying expectations for request parameters by using the
withQueryParam()
method, we should configure the expected URL by using path based matching.
P.S. You can get the example application of this blog post from Github.