Performing Requests

This section shows how to use MockMvcTester to perform requests and its integration with AssertJ to verify responses.

MockMvcTester provides a fluent API to compose the request that reuses the same MockHttpServletRequestBuilder as the Hamcrest support, except that there is no need to import a static method. The builder that is returned is AssertJ-aware so that wrapping it in the regular assertThat() factory method triggers the exchange and provides access to a dedicated Assert object for MvcTestResult.

Here is a simple example that performs a POST on /hotels/42 and configures the request to specify an Accept header:

  • Java

  • Kotlin

assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
		. // ...
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
	. // ...

AssertJ often consists of multiple assertThat() statements to validate the different parts of the exchange. Rather than having a single statement as in the case above, you can use .exchange() to return a MvcTestResult that can be used in multiple assertThat statements:

  • Java

  • Kotlin

MvcTestResult result = mockMvc.post().uri("/hotels/{id}", 42)
		.accept(MediaType.APPLICATION_JSON).exchange();
assertThat(result). // ...
val result = mockMvc.post().uri("/hotels/{id}", 42)
	.accept(MediaType.APPLICATION_JSON).exchange()
assertThat(result)
	. // ...

You can specify query parameters in URI template style, as the following example shows:

  • Java

  • Kotlin

assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
		. // ...
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
	. // ...

You can also add Servlet request parameters that represent either query or form parameters, as the following example shows:

  • Java

  • Kotlin

assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
		. // ...
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
	. // ...

If application code relies on Servlet request parameters and does not check the query string explicitly (as is most often the case), it does not matter which option you use. Keep in mind, however, that query parameters provided with the URI template are decoded while request parameters provided through the param(…​) method are expected to already be decoded.

Async

If the processing of the request is done asynchronously, exchange() waits for the completion of the request so that the result to assert is effectively immutable. The default timeout is 10 seconds but it can be controlled on a request-by-request basis as shown in the following example:

  • Java

  • Kotlin

assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
		. // ...
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
	. // ...

If you prefer to get the raw result and manage the lifecycle of the asynchronous request yourself, use asyncExchange rather than exchange.

Multipart

You can perform file upload requests that internally use MockMultipartHttpServletRequest so that there is no actual parsing of a multipart request. Rather, you have to set it up to be similar to the following example:

  • Java

  • Kotlin

assertThat(mockMvc.post().uri("/upload").multipart()
		.file("file1.txt", "Hello".getBytes(StandardCharsets.UTF_8))
		.file("file2.txt", "World".getBytes(StandardCharsets.UTF_8)))
	. // ...
assertThat(mockMvc.post().uri("/upload").multipart()
		.file("file1.txt", "Hello".toByteArray(StandardCharsets.UTF_8))
		.file("file2.txt", "World".toByteArray(StandardCharsets.UTF_8)))
	. // ...

Using Servlet and Context Paths

In most cases, it is preferable to leave the context path and the Servlet path out of the request URI. If you must test with the full request URI, be sure to set the contextPath and servletPath accordingly so that request mappings work, as the following example shows:

  • Java

  • Kotlin

assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
		.contextPath("/app").servletPath("/main"))
		. // ...
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
		.contextPath("/app").servletPath("/main"))
	. // ...

In the preceding example, it would be cumbersome to set the contextPath and servletPath with every performed request. Instead, you can set up default request properties, as the following example shows:

  • Java

  • Kotlin

MockMvcTester mockMvc = MockMvcTester.of(List.of(new HotelController()),
		builder -> builder.defaultRequest(get("/")
				.contextPath("/app").servletPath("/main")
				.accept(MediaType.APPLICATION_JSON)).build());
val mockMvc =
	MockMvcTester.of(listOf(HotelController())) { builder: StandaloneMockMvcBuilder ->
		builder.defaultRequest<StandaloneMockMvcBuilder>(
			MockMvcRequestBuilders.get("/")
				.contextPath("/app").servletPath("/main")
				.accept(MediaType.APPLICATION_JSON)
		).build()
	}

The preceding properties affect every request performed through the mockMvc instance. If the same property is also specified on a given request, it overrides the default value. That is why the HTTP method and URI in the default request do not matter, since they must be specified on every request.