Document AssertJ support for MockMvc

This commit restructures the section on MockMvc so that the anchors
are easier to read. The standard integration has moved to a
Hamcrest Integration section  at the same level as HtmlUnit Integration,
and a new AssertJ Integration section has been created.

Closes gh-32454
This commit is contained in:
Stéphane Nicoll 2024-06-21 12:50:36 +02:00
parent 7d236e29bb
commit d43dba63a1
54 changed files with 1432 additions and 272 deletions

View File

@ -49,6 +49,7 @@ dependencies {
api(project(":spring-webmvc"))
api(project(":spring-context-support"))
api(project(":spring-aspects"))
api(project(":spring-test"))
api(project(":spring-websocket"))
api("org.jetbrains.kotlin:kotlin-stdlib")

View File

@ -142,23 +142,30 @@
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/spring-mvc-test-framework.adoc[]
*** xref:testing/spring-mvc-test-framework/server.adoc[]
*** xref:testing/spring-mvc-test-framework/server-static-imports.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-options.adoc[]
*** xref:testing/spring-mvc-test-framework/server-setup-steps.adoc[]
*** xref:testing/spring-mvc-test-framework/server-performing-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-defining-expectations.adoc[]
*** xref:testing/spring-mvc-test-framework/async-requests.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-streaming-response.adoc[]
*** xref:testing/spring-mvc-test-framework/server-filters.adoc[]
*** xref:testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/spring-mvc-test-framework/server-resources.adoc[]
*** xref:testing/spring-mvc-test-framework/server-htmlunit.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc[]
**** xref:testing/spring-mvc-test-framework/server-htmlunit/geb.adoc[]
** xref:testing/mockmvc.adoc[]
*** xref:testing/mockmvc/overview.adoc[]
*** xref:testing/mockmvc/setup-options.adoc[]
*** xref:testing/mockmvc/hamcrest.adoc[]
**** xref:testing/mockmvc/hamcrest/static-imports.adoc[]
**** xref:testing/mockmvc/hamcrest/setup.adoc[]
**** xref:testing/mockmvc/hamcrest/setup-steps.adoc[]
**** xref:testing/mockmvc/hamcrest/requests.adoc[]
**** xref:testing/mockmvc/hamcrest/expectations.adoc[]
**** xref:testing/mockmvc/hamcrest/async-requests.adoc[]
**** xref:testing/mockmvc/hamcrest/vs-streaming-response.adoc[]
**** xref:testing/mockmvc/hamcrest/filters.adoc[]
*** xref:testing/mockmvc/assertj.adoc[]
**** xref:testing/mockmvc/assertj/setup.adoc[]
**** xref:testing/mockmvc/assertj/requests.adoc[]
**** xref:testing/mockmvc/assertj/assertions.adoc[]
**** xref:testing/mockmvc/assertj/integration.adoc[]
*** xref:testing/mockmvc/htmlunit.adoc[]
**** xref:testing/mockmvc/htmlunit/why.adoc[]
**** xref:testing/mockmvc/htmlunit/mah.adoc[]
**** xref:testing/mockmvc/htmlunit/webdriver.adoc[]
**** xref:testing/mockmvc/htmlunit/geb.adoc[]
*** xref:testing/mockmvc/vs-end-to-end-integration-tests.adoc[]
*** xref:testing/mockmvc/resources.adoc[]
** xref:testing/spring-mvc-test-client.adoc[]
** xref:testing/appendix.adoc[]
*** xref:testing/annotations.adoc[]

View File

@ -30,7 +30,7 @@ integration support, and the rest of this chapter then focuses on dedicated topi
* xref:testing/support-jdbc.adoc[JDBC Testing Support]
* xref:testing/testcontext-framework.adoc[Spring TestContext Framework]
* xref:testing/webtestclient.adoc[WebTestClient]
* xref:testing/spring-mvc-test-framework.adoc[MockMvc]
* xref:testing/mockmvc.adoc[MockMvc]
* xref:testing/spring-mvc-test-client.adoc[Testing Client Applications]
* xref:testing/annotations.adoc[Annotations]

View File

@ -0,0 +1,16 @@
[[mockmvc]]
= MockMvc
:page-section-summary-toc: 1
MockMvc provides support for testing Spring MVC applications. It performs full Spring MVC
request handling but via mock request and response objects instead of a running server.
MockMvc can be used on its own to perform requests and verify responses responses using
Hamcrest, or through `MockMvcTester` that provides a fluent API using AssertJ. Finally,
it can also be used through the xref:testing/webtestclient.adoc[WebTestClient] where
MockMvc is plugged in as the server to handle requests with. The advantage of
`WebTestClient` is the option to work with higher level objects instead of raw data as
well as the ability to switch to full, end-to-end HTTP tests against a live server and
use the same test API.

View File

@ -0,0 +1,16 @@
[[mockmvc-tester]]
= AssertJ Integration
:page-section-summary-toc: 1
The AssertJ integration builds on top of plain `MockMvc` with several differences:
* There is no need to use static imports as both the requests and assertions can be
crafted using a fluent API.
* Unresolved exceptions are handled consistently so that your tests do not need to
throw (or catch) `Exception`.
* By default, the result to assert is complete whether the processing is asynchronous
or not. In other words, there is no need for special handling for Async requests.
`MockMvcTester` is the entry point for the AssertJ support. It allows to craft the
request and return a result that is AssertJ compatible so that it can be wrapped in
a standard `assertThat()` method.

View File

@ -0,0 +1,49 @@
[[mockmvc-tester-assertions]]
= Defining Expectations
Assertions work the same way as any AssertJ assertions. The support provides dedicated
assert objects for the various pieces of the `MvcTestResult`, as shown in the following
example:
include-code::./HotelControllerTests[tag=get,indent=0]
If a request fails, the exchange does not throw the exception. Rather, you can assert
that the result of the exchange has failed:
include-code::./HotelControllerTests[tag=failure,indent=0]
The request could also fail unexpectedly, that is the exception thrown by the handler
has not been handled and is thrown as is. You can still use `.hasFailed()` and
`.failure()` but any attempt to access part of the result will throw an exception as
the exchange hasn't completed.
[[mockmvc-tester-assertions-json]]
== JSON Support
The AssertJ support for `MvcTestResult` provides JSON support via `bodyJson()`.
If https://github.com/jayway/JsonPath[JSONPath] is available, you can apply an expression
on the JSON document. The returned value provides convenient methods to return a dedicated
assert object for the various supported JSON data types:
include-code::./FamilyControllerTests[tag=extract-asmap,indent=0]
You can also convert the raw content to any of your data types as long as the message
converter is configured properly:
include-code::./FamilyControllerTests[tag=extract-convert,indent=0]
Converting to a target `Class` provides a generic assert object. For more complex types,
you may want to use `AssertFactory` instead that returns a dedicated assert type, if
possible:
include-code::./FamilyControllerTests[tag=extract-convert-assert-factory,indent=0]
https://jsonassert.skyscreamer.org[JSONAssert] is also supported. The body of the
response can be matched against a `Resource` or a content. If the content ends with
`.json ` we look for a file matching that name on the classpath:
include-code::./FamilyControllerTests[tag=assert-file,indent=0]
If you prefer to use another library, you can provide an implementation of
{spring-framework-api}/test/json/JsonComparator.html[`JsonComparator`].

View File

@ -0,0 +1,23 @@
[[mockmvc-tester-integration]]
= MockMvc integration
If you want to use the AssertJ support but have invested in the original `MockMvc`
API, `MockMvcTester` offers several ways to integrate with it.
If you have your own `RequestBuilder` implementation, you can trigger the processing
of the request using `perform`. The example below showcases how the query can be
crafted with the original API:
include-code::./HotelControllerTests[tag=perform,indent=0]
Similarly, if you have crafted custom matchers that you use with the `.andExpect` feature
of `MockMvc` you can use them via `.matches`. In the example below, we rewrite the
preceding example to assert the status with the `ResultMatcher` implementation that
`MockMvc` provides:
include-code::./HotelControllerTests[tag=matches,indent=0]
`MockMvc` also defines a `ResultHandler` contract that lets you execute arbitrary actions
on `MvcResult`. If you have implemented this contract you can invoke it using `.apply`.

View File

@ -0,0 +1,83 @@
[[mockmvc-tester-requests]]
= 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:
include-code::./HotelControllerTests[tag=post,indent=0]
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:
include-code::./HotelControllerTests[tag=post-exchange,indent=0]
You can specify query parameters in URI template style, as the following example shows:
include-code::./HotelControllerTests[tag=query-parameters,indent=0]
You can also add Servlet request parameters that represent either query or form
parameters, as the following example shows:
include-code::./HotelControllerTests[tag=parameters,indent=0]
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.
[[mockmvc-tester-requests-async]]
== 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:
include-code::./AsyncControllerTests[tag=duration,indent=0]
If you prefer to get the raw result and manage the lifecycle of the asynchronous
request yourself, use `asyncExchange` rather than `exchange`.
[[mockmvc-tester-requests-multipart]]
== 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:
include-code::./MultipartControllerTests[tag=snippet,indent=0]
[[mockmvc-tester-requests-paths]]
== 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:
include-code::./HotelControllerTests[tag=context-servlet-paths,indent=0]
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:
include-code::./HotelControllerTests[tag=default-customizations,indent=0]
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.

View File

@ -0,0 +1,30 @@
[[mockmvc-tester-setup]]
= Configuring MockMvcTester
`MockMvcTester` can be setup in one of two ways. One is to point directly to the
controllers you want to test and programmatically configure Spring MVC infrastructure.
The second is to point to Spring configuration with Spring MVC and controller
infrastructure in it.
TIP: For a comparison of those two modes, check xref:testing/mockmvc/setup-options.adoc[Setup Options].
To set up `MockMvcTester` for testing a specific controller, use the following:
include-code::./AccountControllerStandaloneTests[tag=snippet,indent=0]
To set up `MockMvcTester` through Spring configuration, use the following:
include-code::./AccountControllerIntegrationTests[tag=snippet,indent=0]
`MockMvcTester` can convert the JSON response body, or the result of a JSONPath expression,
to one of your domain object as long as the relevant `HttpMessageConverter` is registered.
If you use Jackson to serialize content to JSON, the following example registers the
converter:
include-code::./converter/AccountControllerIntegrationTests[tag=snippet,indent=0]
NOTE: The above assumes the converter has been registered as a Bean.
Finally, if you have a `MockMvc` instance handy, you can create a `MockMvcTester` by
providing the `MockMvc` instance to use using the `create` factory method.

View File

@ -0,0 +1,7 @@
[[mockmvc-server]]
= Hamcrest Integration
:page-section-summary-toc: 1
Plain `MockMvc` provides an API to build the request using a builder-style approach
that can be initiated with static imports. Hamcrest is used to define expectations and
it provides many out-of-the-box options for common needs.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-async-requests]]
[[mockmvc-async-requests]]
= Async Requests
This section shows how to use MockMvc on its own to test asynchronous request handling.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-defining-expectations]]
[[mockmvc-server-defining-expectations]]
= Defining Expectations
You can define expectations by appending one or more `andExpect(..)` calls after

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-filters]]
[[mockmvc-server-filters]]
= Filter Registrations
:page-section-summary-toc: 1

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-performing-requests]]
[[mockmvc-server-performing-requests]]
= Performing Requests
This section shows how to use MockMvc on its own to perform requests and verify responses.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-setup-steps]]
[[mockmvc-server-setup-steps]]
= Setup Features
No matter which MockMvc builder you use, all `MockMvcBuilder` implementations provide

View File

@ -0,0 +1,100 @@
[[mockmvc-setup]]
= Configuring MockMvc
MockMvc can be setup in one of two ways. One is to point directly to the controllers you
want to test and programmatically configure Spring MVC infrastructure. The second is to
point to Spring configuration with Spring MVC and controller infrastructure in it.
TIP: For a comparison of those two modes, check xref:testing/mockmvc/setup-options.adoc[Setup Options].
To set up MockMvc for testing a specific controller, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class MyWebTests {
lateinit var mockMvc : MockMvc
@BeforeEach
fun setup() {
mockMvc = MockMvcBuilders.standaloneSetup(AccountController()).build()
}
// ...
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-controller-config[WebTestClient] which delegates to the same builder
as shown above.
To set up MockMvc through Spring configuration, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@SpringJUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@SpringJUnitWebConfig(locations = ["my-servlet-context.xml"])
class MyWebTests {
lateinit var mockMvc: MockMvc
@BeforeEach
fun setup(wac: WebApplicationContext) {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
}
// ...
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-context-config[WebTestClient] which delegates to the same builder
as shown above.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-static-imports]]
[[mockmvc-server-static-imports]]
= Static Imports
:page-section-summary-toc: 1

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-vs-streaming-response]]
[[mockmvc-vs-streaming-response]]
= Streaming Responses
You can use `WebTestClient` to test xref:testing/webtestclient.adoc#webtestclient-stream[streaming responses]

View File

@ -1,8 +1,8 @@
[[spring-mvc-test-server-htmlunit]]
[[mockmvc-server-htmlunit]]
= HtmlUnit Integration
:page-section-summary-toc: 1
Spring provides integration between xref:testing/spring-mvc-test-framework/server.adoc[MockMvc] and
Spring provides integration between xref:testing/mockmvc/overview.adoc[MockMvc] and
https://htmlunit.sourceforge.io/[HtmlUnit]. This simplifies performing end-to-end testing
when using HTML-based views. This integration lets you:

View File

@ -1,18 +1,18 @@
[[spring-mvc-test-server-htmlunit-geb]]
[[mockmvc-server-htmlunit-geb]]
= MockMvc and Geb
In the previous section, we saw how to use MockMvc with WebDriver. In this section, we
use https://www.gebish.org/[Geb] to make our tests even Groovy-er.
[[spring-mvc-test-server-htmlunit-geb-why]]
[[mockmvc-server-htmlunit-geb-why]]
== Why Geb and MockMvc?
Geb is backed by WebDriver, so it offers many of the
xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-why[same benefits] that we get from
xref:testing/mockmvc/htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-why[same benefits] that we get from
WebDriver. However, Geb makes things even easier by taking care of some of the
boilerplate code for us.
[[spring-mvc-test-server-htmlunit-geb-setup]]
[[mockmvc-server-htmlunit-geb-setup]]
== MockMvc and Geb Setup
We can easily initialize a Geb `Browser` with a Selenium WebDriver that uses MockMvc, as
@ -28,14 +28,14 @@ def setup() {
----
NOTE: This is a simple example of using `MockMvcHtmlUnitDriverBuilder`. For more advanced
usage, see xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-advanced-builder[Advanced `MockMvcHtmlUnitDriverBuilder`].
usage, see xref:testing/mockmvc/htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-advanced-builder[Advanced `MockMvcHtmlUnitDriverBuilder`].
This ensures that any URL referencing `localhost` as the server is directed to our
`MockMvc` instance without the need for a real HTTP connection. Any other URL is
requested by using a network connection as normal. This lets us easily test the use of
CDNs.
[[spring-mvc-test-server-htmlunit-geb-usage]]
[[mockmvc-server-htmlunit-geb-usage]]
== MockMvc and Geb Usage
Now we can use Geb as we normally would but without the need to deploy our application to
@ -62,7 +62,7 @@ forwarded to the current page object. This removes a lot of the boilerplate code
needed when using WebDriver directly.
As with direct WebDriver usage, this improves on the design of our
xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test] by using the Page Object
xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test] by using the Page Object
Pattern. As mentioned previously, we can use the Page Object Pattern with HtmlUnit and
WebDriver, but it is even easier with Geb. Consider our new Groovy-based
`CreateMessagePage` implementation:

View File

@ -1,10 +1,10 @@
[[spring-mvc-test-server-htmlunit-mah]]
[[mockmvc-server-htmlunit-mah]]
= MockMvc and HtmlUnit
This section describes how to integrate MockMvc and HtmlUnit. Use this option if you want
to use the raw HtmlUnit libraries.
[[spring-mvc-test-server-htmlunit-mah-setup]]
[[mockmvc-server-htmlunit-mah-setup]]
== MockMvc and HtmlUnit Setup
First, make sure that you have included a test dependency on
@ -45,14 +45,14 @@ Kotlin::
======
NOTE: This is a simple example of using `MockMvcWebClientBuilder`. For advanced usage,
see xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
see xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
This ensures that any URL that references `localhost` as the server is directed to our
`MockMvc` instance without the need for a real HTTP connection. Any other URL is
requested by using a network connection, as normal. This lets us easily test the use of
CDNs.
[[spring-mvc-test-server-htmlunit-mah-usage]]
[[mockmvc-server-htmlunit-mah-usage]]
== MockMvc and HtmlUnit Usage
Now we can use HtmlUnit as we normally would but without the need to deploy our
@ -77,7 +77,7 @@ Kotlin::
======
NOTE: The default context path is `""`. Alternatively, we can specify the context path,
as described in xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
as described in xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced `MockMvcWebClientBuilder`].
Once we have a reference to the `HtmlPage`, we can then fill out the form and submit it
to create a message, as the following example shows:
@ -144,7 +144,7 @@ Kotlin::
======
The preceding code improves on our
xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc#spring-mvc-test-server-htmlunit-mock-mvc-test[MockMvc test] in a number of ways.
xref:testing/mockmvc/htmlunit/why.adoc#spring-mvc-test-server-htmlunit-mock-mvc-test[MockMvc test] in a number of ways.
First, we no longer have to explicitly verify our form and then create a request that
looks like the form. Instead, we request the form, fill it out, and submit it, thereby
significantly reducing the overhead.
@ -156,7 +156,7 @@ the behavior of JavaScript within our pages.
See the https://htmlunit.sourceforge.io/gettingStarted.html[HtmlUnit documentation] for
additional information about using HtmlUnit.
[[spring-mvc-test-server-htmlunit-mah-advanced-builder]]
[[mockmvc-server-htmlunit-mah-advanced-builder]]
== Advanced `MockMvcWebClientBuilder`
In the examples so far, we have used `MockMvcWebClientBuilder` in the simplest way
@ -275,5 +275,5 @@ This is more verbose, but, by building the `WebClient` with a `MockMvc` instance
the full power of MockMvc at our fingertips.
TIP: For additional information on creating a `MockMvc` instance, see
xref:testing/spring-mvc-test-framework/server-setup-options.adoc[Setup Choices].
xref:testing/mockmvc/hamcrest/setup.adoc[Configuring MockMvc].

View File

@ -1,11 +1,11 @@
[[spring-mvc-test-server-htmlunit-webdriver]]
[[mockmvc-server-htmlunit-webdriver]]
= MockMvc and WebDriver
In the previous sections, we have seen how to use MockMvc in conjunction with the raw
HtmlUnit APIs. In this section, we use additional abstractions within the Selenium
https://docs.seleniumhq.org/projects/webdriver/[WebDriver] to make things even easier.
[[spring-mvc-test-server-htmlunit-webdriver-why]]
[[mockmvc-server-htmlunit-webdriver-why]]
== Why WebDriver and MockMvc?
We can already use HtmlUnit and MockMvc, so why would we want to use WebDriver? The
@ -162,11 +162,11 @@ https://github.com/SeleniumHQ/selenium/wiki/PageObjects[Page Object Pattern]. Wh
can certainly do this with HtmlUnit, WebDriver provides some tools that we explore in the
following sections to make this pattern much easier to implement.
[[spring-mvc-test-server-htmlunit-webdriver-setup]]
[[mockmvc-server-htmlunit-webdriver-setup]]
== MockMvc and WebDriver Setup
To use Selenium WebDriver with the Spring MVC Test framework, make sure that your project
includes a test dependency on `org.seleniumhq.selenium:selenium-htmlunit3-driver`.
To use Selenium WebDriver with `MockMvc`, make sure that your project includes a test
dependency on `org.seleniumhq.selenium:selenium-htmlunit3-driver`.
We can easily create a Selenium WebDriver that integrates with MockMvc by using the
`MockMvcHtmlUnitDriverBuilder` as the following example shows:
@ -203,14 +203,14 @@ Kotlin::
======
NOTE: This is a simple example of using `MockMvcHtmlUnitDriverBuilder`. For more advanced
usage, see xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-advanced-builder[Advanced `MockMvcHtmlUnitDriverBuilder`].
usage, see xref:testing/mockmvc/htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-advanced-builder[Advanced `MockMvcHtmlUnitDriverBuilder`].
The preceding example ensures that any URL that references `localhost` as the server is
directed to our `MockMvc` instance without the need for a real HTTP connection. Any other
URL is requested by using a network connection, as normal. This lets us easily test the
use of CDNs.
[[spring-mvc-test-server-htmlunit-webdriver-usage]]
[[mockmvc-server-htmlunit-webdriver-usage]]
== MockMvc and WebDriver Usage
Now we can use WebDriver as we normally would but without the need to deploy our
@ -259,9 +259,9 @@ Kotlin::
======
--
This improves on the design of our xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test]
This improves on the design of our xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test]
by leveraging the Page Object Pattern. As we mentioned in
xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-why[Why WebDriver and MockMvc?], we can use the Page Object Pattern
xref:testing/mockmvc/htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-why[Why WebDriver and MockMvc?], we can use the Page Object Pattern
with HtmlUnit, but it is much easier with WebDriver. Consider the following
`CreateMessagePage` implementation:
@ -451,7 +451,7 @@ Kotlin::
For additional information on using WebDriver, see the Selenium
https://github.com/SeleniumHQ/selenium/wiki/Getting-Started[WebDriver documentation].
[[spring-mvc-test-server-htmlunit-webdriver-advanced-builder]]
[[mockmvc-server-htmlunit-webdriver-advanced-builder]]
== Advanced `MockMvcHtmlUnitDriverBuilder`
In the examples so far, we have used `MockMvcHtmlUnitDriverBuilder` in the simplest way
@ -570,5 +570,5 @@ This is more verbose, but, by building the `WebDriver` with a `MockMvc` instance
the full power of MockMvc at our fingertips.
TIP: For additional information on creating a `MockMvc` instance, see
xref:testing/spring-mvc-test-framework/server-setup-options.adoc[Setup Choices].
xref:testing/mockmvc/hamcrest/setup.adoc[Configuring MockMvc].

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-htmlunit-why]]
[[mockmvc-server-htmlunit-why]]
= Why HtmlUnit Integration?
The most obvious question that comes to mind is "`Why do I need this?`" The answer is
@ -94,7 +94,7 @@ follows:
======
Java::
+
[[spring-mvc-test-server-htmlunit-mock-mvc-test]]
[[mockmvc-server-htmlunit-mock-mvc-test]]
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
String summaryParamName = "summary";
@ -151,7 +151,7 @@ the input to a user for creating a message. In addition, our form view can poten
use additional resources that impact the behavior of the page, such as JavaScript
validation.
[[spring-mvc-test-server-htmlunit-why-integration]]
[[mockmvc-server-htmlunit-why-integration]]
== Integration Testing to the Rescue?
To resolve the issues mentioned earlier, we could perform end-to-end integration testing,
@ -181,23 +181,23 @@ and without side effects. We can then implement a small number of true end-to-en
integration tests that validate simple workflows to ensure that everything works together
properly.
[[spring-mvc-test-server-htmlunit-why-mockmvc]]
[[mockmvc-server-htmlunit-why-mockmvc]]
== Enter HtmlUnit Integration
So how can we achieve a balance between testing the interactions of our pages and still
retain good performance within our test suite? The answer is: "`By integrating MockMvc
with HtmlUnit.`"
[[spring-mvc-test-server-htmlunit-options]]
[[mockmvc-server-htmlunit-options]]
== HtmlUnit Integration Options
You have a number of options when you want to integrate MockMvc with HtmlUnit:
* xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc[MockMvc and HtmlUnit]: Use this option if you
* xref:testing/mockmvc/htmlunit/mah.adoc[MockMvc and HtmlUnit]: Use this option if you
want to use the raw HtmlUnit libraries.
* xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc[MockMvc and WebDriver]: Use this option to
* xref:testing/mockmvc/htmlunit/webdriver.adoc[MockMvc and WebDriver]: Use this option to
ease development and reuse code between integration and end-to-end testing.
* xref:testing/spring-mvc-test-framework/server-htmlunit/geb.adoc[MockMvc and Geb]: Use this option if you want to
* xref:testing/mockmvc/htmlunit/geb.adoc[MockMvc and Geb]: Use this option if you want to
use Groovy for testing, ease development, and reuse code between integration and
end-to-end testing.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server]]
[[mockmvc-overview]]
= Overview
:page-section-summary-toc: 1
@ -8,17 +8,17 @@ mappings, data binding, message conversion, type conversion, validation, and nor
do they involve any of the supporting `@InitBinder`, `@ModelAttribute`, or
`@ExceptionHandler` methods.
The Spring MVC Test framework, also known as `MockMvc`, aims to provide more complete
testing for Spring MVC controllers without a running server. It does that by invoking
the `DispatcherServlet` and passing
`MockMvc` aims to provide more complete testing for Spring MVC controllers without a
running server. It does that by invoking the `DispatcherServlet` and passing
xref:testing/unit.adoc#mock-objects-servlet["`mock`" implementations of the Servlet API] from the
`spring-test` module which replicates the full Spring MVC request handling without
a running server.
MockMvc is a server side test framework that lets you verify most of the functionality
of a Spring MVC application using lightweight and targeted tests. You can use it on
its own to perform requests and to verify responses, or you can also use it through
the xref:testing/webtestclient.adoc[WebTestClient] API with MockMvc plugged in as the server to handle requests
with.
its own to perform requests and to verify responses using Hamcrest, or through
`MockMvcTester` that provides a fluent API using AssertJ. Finally, you can also use it
through the xref:testing/webtestclient.adoc[WebTestClient] API with MockMvc plugged in
as the server to handle requests with.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-server-resources]]
[[mockmvc-server-resources]]
= Further Examples
:page-section-summary-toc: 1

View File

@ -0,0 +1,29 @@
[[mockmvc-server-setup-options]]
= Setup Options
MockMvc can be setup in one of two ways. One is to point directly to the controllers you
want to test and programmatically configure Spring MVC infrastructure. The second is to
point to Spring configuration with Spring MVC and controller infrastructure in it.
Which setup option should you use?
The use of an `ApplicationContext` loads your actual Spring MVC configuration, resulting
The `WebApplicationContext`-based test loads your actual Spring MVC configuration,
resulting in a more complete integration test. Since the TestContext framework caches
the loaded Spring configuration, it helps keep tests running fast, even as you introduce
more tests in your test suite using the same configuration. Furthermore, you can
override services used by your controller using `@MockitoBean` to remain focused on
testing the web layer.
The standalone test, on the other hand, is a little closer to a unit test. It tests one
controller at a time. You can manually inject the controller with mock dependencies, and
it does not involve loading Spring configuration. Such tests are more focused on style
and make it easier to see which controller is being tested, whether any specific Spring
MVC configuration is required to work, and so on. The standalone setup is also a very
convenient way to write ad-hoc tests to verify specific behavior or to debug an issue.
As with most "`integration versus unit testing`" debates, there is no right or wrong
answer. However, using standalone tests does imply the need for additional integration
tests to verify your Spring MVC configuration. Alternatively, you can write all your
tests with a `WebApplicationContext`, so that they always test against your actual Spring
MVC configuration.

View File

@ -1,4 +1,4 @@
[[spring-mvc-test-vs-end-to-end-integration-tests]]
[[mockmvc-vs-end-to-end-integration-tests]]
= MockMvc vs End-to-End Tests
MockMvc is built on Servlet API mock implementations from the

View File

@ -1,15 +0,0 @@
[[spring-mvc-test-framework]]
= MockMvc
:page-section-summary-toc: 1
The Spring MVC Test framework, also known as MockMvc, provides support for testing Spring
MVC applications. It performs full Spring MVC request handling but via mock request and
response objects instead of a running server.
MockMvc can be used on its own to perform requests and verify responses. It can also be
used through the xref:testing/webtestclient.adoc[WebTestClient] where MockMvc is plugged in as the server to handle
requests with. The advantage of `WebTestClient` is the option to work with higher level
objects instead of raw data as well as the ability to switch to full, end-to-end HTTP
tests against a live server and use the same test API.

View File

@ -1,181 +0,0 @@
[[spring-mvc-test-server-setup-options]]
= Setup Choices
MockMvc can be setup in one of two ways. One is to point directly to the controllers you
want to test and programmatically configure Spring MVC infrastructure. The second is to
point to Spring configuration with Spring MVC and controller infrastructure in it.
To set up MockMvc for testing a specific controller, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
class MyWebTests {
lateinit var mockMvc : MockMvc
@BeforeEach
fun setup() {
mockMvc = MockMvcBuilders.standaloneSetup(AccountController()).build()
}
// ...
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-controller-config[WebTestClient] which delegates to the same builder
as shown above.
To set up MockMvc through Spring configuration, use the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@SpringJUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@SpringJUnitWebConfig(locations = ["my-servlet-context.xml"])
class MyWebTests {
lateinit var mockMvc: MockMvc
@BeforeEach
fun setup(wac: WebApplicationContext) {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
}
// ...
}
----
======
Or you can also use this setup when testing through the
xref:testing/webtestclient.adoc#webtestclient-context-config[WebTestClient] which delegates to the same builder
as shown above.
Which setup option should you use?
The `webAppContextSetup` loads your actual Spring MVC configuration, resulting in a more
complete integration test. Since the TestContext framework caches the loaded Spring
configuration, it helps keep tests running fast, even as you introduce more tests in your
test suite. Furthermore, you can inject mock services into controllers through Spring
configuration to remain focused on testing the web layer. The following example declares
a mock service with Mockito:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="accountService" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg type="java.lang.Class" value="org.example.AccountService"/>
<constructor-arg type="java.lang.String" value="accountService"/>
</bean>
----
You can then inject the mock service into the test to set up and verify your
expectations, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
@SpringJUnitWebConfig(locations = "test-servlet-context.xml")
class AccountTests {
@Autowired
AccountService accountService;
MockMvc mockMvc;
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@SpringJUnitWebConfig(locations = ["test-servlet-context.xml"])
class AccountTests {
@Autowired
lateinit var accountService: AccountService
lateinit var mockMvc: MockMvc
@BeforeEach
fun setup(wac: WebApplicationContext) {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
}
// ...
}
----
======
The `standaloneSetup`, on the other hand, is a little closer to a unit test. It tests one
controller at a time. You can manually inject the controller with mock dependencies, and
it does not involve loading Spring configuration. Such tests are more focused on style
and make it easier to see which controller is being tested, whether any specific Spring
MVC configuration is required to work, and so on. The `standaloneSetup` is also a very
convenient way to write ad-hoc tests to verify specific behavior or to debug an issue.
As with most "`integration versus unit testing`" debates, there is no right or wrong
answer. However, using the `standaloneSetup` does imply the need for additional
`webAppContextSetup` tests in order to verify your Spring MVC configuration.
Alternatively, you can write all your tests with `webAppContextSetup`, in order to always
test against your actual Spring MVC configuration.

View File

@ -68,8 +68,8 @@ or alternative Servlet API mock objects (such as http://www.mockobjects.com[Mock
TIP: Since Spring Framework 6.0, the mock objects in `org.springframework.mock.web` are
based on the Servlet 6.0 API.
The Spring MVC Test framework builds on the mock Servlet API objects to provide an
integration testing framework for Spring MVC. See xref:testing/spring-mvc-test-framework.adoc[MockMvc].
MockMvc builds on the mock Servlet API objects to provide an integration testing
framework for Spring MVC. See xref:testing/mockmvc.adoc[MockMvc].
[[mock-objects-web-reactive]]
@ -165,4 +165,4 @@ combined with `MockHttpServletRequest`, `MockHttpSession`, and so on from Spring
xref:testing/unit.adoc#mock-objects-servlet[Servlet API mocks]. For thorough integration testing of your
Spring MVC and REST `Controller` classes in conjunction with your `WebApplicationContext`
configuration for Spring MVC, use the
xref:testing/spring-mvc-test-framework.adoc[Spring MVC Test Framework] instead.
xref:testing/mockmvc.adoc[MockMvc] instead.

View File

@ -51,7 +51,7 @@ For Spring MVC, use the following which delegates to the
{spring-framework-api}/test/web/servlet/setup/StandaloneMockMvcBuilder.html[StandaloneMockMvcBuilder]
to load infrastructure equivalent to the xref:web/webmvc/mvc-config.adoc[WebMvc Java config],
registers the given controller(s), and creates an instance of
xref:testing/spring-mvc-test-framework.adoc[MockMvc] to handle requests:
xref:testing/mockmvc.adoc[MockMvc] to handle requests:
[tabs]
======
@ -128,7 +128,7 @@ Kotlin::
For Spring MVC, use the following where the Spring `ApplicationContext` is passed to
{spring-framework-api}/test/web/servlet/setup/MockMvcBuilders.html#webAppContextSetup-org.springframework.web.context.WebApplicationContext-[MockMvcBuilders.webAppContextSetup]
to create a xref:testing/spring-mvc-test-framework.adoc[MockMvc] instance to handle
to create a xref:testing/mockmvc.adoc[MockMvc] instance to handle
requests:
[tabs]

View File

@ -16,7 +16,7 @@ See xref:testing/testcontext-framework.adoc[TestContext Framework] for more deta
* Spring MVC Test: A framework, also known as `MockMvc`, for testing annotated controllers
through the `DispatcherServlet` (that is, supporting annotations), complete with the
Spring MVC infrastructure but without an HTTP server.
See xref:testing/spring-mvc-test-framework.adoc[Spring MVC Test] for more details.
See xref:testing/mockmvc.adoc[Spring MVC Test] for more details.
* Client-side REST: `spring-test` provides a `MockRestServiceServer` that you can use as
a mock server for testing client-side code that internally uses the `RestTemplate`.

View File

@ -0,0 +1,50 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterassertions;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
public class HotelControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new HotelController());
void getHotel() {
// tag::get[]
assertThat(mockMvc.get().uri("/hotels/{id}", 42))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
.bodyJson().isLenientlyEqualTo("sample/hotel-42.json");
// end::get[]
}
void getHotelInvalid() {
// tag::failure[]
assertThat(mockMvc.get().uri("/hotels/{id}", -1))
.hasFailed()
.hasStatus(HttpStatus.BAD_REQUEST)
.failure().hasMessageContaining("Identifier should be positive");
// end::failure[]
}
static class HotelController {}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterassertionsjson;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
class FamilyControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new FamilyController());
void extractingPathAsMap() {
// tag::extract-asmap[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members[0]")
.asMap()
.contains(entry("name", "Homer"));
// end::extract-asmap[]
}
void extractingPathAndConvertWithType() {
// tag::extract-convert[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members[0]")
.convertTo(Member.class)
.satisfies(member -> assertThat(member.name).isEqualTo("Homer"));
// end::extract-convert[]
}
void extractingPathAndConvertWithAssertFactory() {
// tag::extract-convert-assert-factory[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members")
.convertTo(InstanceOfAssertFactories.list(Member.class))
.hasSize(5)
.element(0).satisfies(member -> assertThat(member.name).isEqualTo("Homer"));
// end::extract-convert-assert-factory[]
}
void assertTheSimpsons() {
// tag::assert-file[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.isStrictlyEqualTo("sample/simpsons.json");
// end::assert-file[]
}
static class FamilyController {}
record Member(String name) {}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterintegration;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class HotelControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new HotelController());
void perform() {
// tag::perform[]
// Static import on MockMvcRequestBuilders.get
assertThat(mockMvc.perform(get("/hotels/{id}", 42)))
.hasStatusOk();
// end::perform[]
}
void performWithCustomMatcher() {
// tag::matches[]
// Static import on MockMvcResultMatchers.status
assertThat(mockMvc.get().uri("/hotels/{id}", 42))
.matches(status().isOk());
// end::matches[]
}
static class HotelController {}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequests;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.test.web.servlet.assertj.MvcTestResult;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
* @author Stephane Nicoll
*/
public class HotelControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new HotelController());
void createHotel() {
// tag::post[]
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
. // ...
// end::post[]
hasStatusOk();
}
void createHotelMultipleAssertions() {
// tag::post-exchange[]
MvcTestResult result = mockMvc.post().uri("/hotels/{id}", 42)
.accept(MediaType.APPLICATION_JSON).exchange();
assertThat(result). // ...
// end::post-exchange[]
hasStatusOk();
}
void queryParameters() {
// tag::query-parameters[]
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
. // ...
// end::query-parameters[]
hasStatusOk();
}
void parameters() {
// tag::parameters[]
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
. // ...
// end::parameters[]
hasStatusOk();
}
static class HotelController {}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestsasync;
import java.time.Duration;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
public class AsyncControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new AsyncController());
void asyncExchangeWithCustomTimeToWait() {
// tag::duration[]
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
. // ...
// end::duration[]
hasStatusOk();
}
static class AsyncController {}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestsmultipart;
import java.nio.charset.StandardCharsets;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
public class MultipartControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new MultipartController());
void multiPart() {
// tag::snippet[]
assertThat(mockMvc.post().uri("/upload").multipart()
.file("file1.txt", "Hello".getBytes(StandardCharsets.UTF_8))
.file("file2.txt", "World".getBytes(StandardCharsets.UTF_8)))
. // ...
// end::snippet[]
hasStatusOk();
}
static class MultipartController {}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestspaths;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
* @author Stephane Nicoll
*/
public class HotelControllerTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new HotelController());
void contextAndServletPaths() {
// tag::context-servlet-paths[]
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
.contextPath("/app").servletPath("/main"))
. // ...
// end::context-servlet-paths[]
hasStatusOk();
}
void configureMockMvcTesterWithDefaultSettings() {
// tag::default-customizations[]
MockMvcTester mockMvc = MockMvcTester.of(List.of(new HotelController()),
builder -> builder.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON)).build());
// end::default-customizations[]
}
static class HotelController {}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AccountController {
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.context.WebApplicationContext;
// tag::snippet[]
@SpringJUnitWebConfig(ApplicationWebConfiguration.class)
class AccountControllerIntegrationTests {
private final MockMvcTester mockMvc;
AccountControllerIntegrationTests(@Autowired WebApplicationContext wac) {
this.mockMvc = MockMvcTester.from(wac);
}
// ...
}
// end::snippet[]

View File

@ -0,0 +1,29 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
// tag::snippet[]
public class AccountControllerStandaloneTests {
private final MockMvcTester mockMvc = MockMvcTester.of(new AccountController());
// ...
}
// end::snippet[]

View File

@ -0,0 +1,25 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
public class ApplicationWebConfiguration {
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup.converter;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup.ApplicationWebConfiguration;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.context.WebApplicationContext;
// tag::snippet[]
@SpringJUnitWebConfig(ApplicationWebConfiguration.class)
class AccountControllerIntegrationTests {
private final MockMvcTester mockMvc;
AccountControllerIntegrationTests(@Autowired WebApplicationContext wac) {
this.mockMvc = MockMvcTester.from(wac).withHttpMessageConverters(
List.of(wac.getBean(AbstractJackson2HttpMessageConverter.class)));
}
// ...
}
// end::snippet[]

View File

@ -0,0 +1,48 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterassertions
import org.assertj.core.api.Assertions.assertThat
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.assertj.MockMvcTester
class HotelControllerTests {
private val mockMvc = MockMvcTester.of(HotelController())
fun getHotel() {
// tag::get[]
assertThat(mockMvc.get().uri("/hotels/{id}", 42))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
.bodyJson().isLenientlyEqualTo("sample/hotel-42.json")
// end::get[]
}
fun getHotelInvalid() {
// tag::failure[]
assertThat(mockMvc.get().uri("/hotels/{id}", -1))
.hasFailed()
.hasStatus(HttpStatus.BAD_REQUEST)
.failure().hasMessageContaining("Identifier should be positive")
// end::failure[]
}
class HotelController
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterassertionsjson
import org.assertj.core.api.Assertions.*
import org.assertj.core.api.InstanceOfAssertFactories
import org.assertj.core.api.ThrowingConsumer
import org.springframework.test.web.servlet.assertj.MockMvcTester
/**
*
* @author Stephane Nicoll
*/
class FamilyControllerTests {
private val mockMvc = MockMvcTester.of(FamilyController())
fun extractingPathAsMap() {
// tag::extract-asmap[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members[0]")
.asMap()
.contains(entry("name", "Homer"))
// end::extract-asmap[]
}
fun extractingPathAndConvertWithType() {
// tag::extract-convert[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members[0]")
.convertTo(Member::class.java)
.satisfies(ThrowingConsumer { member: Member ->
assertThat(member.name).isEqualTo("Homer")
})
// end::extract-convert[]
}
fun extractingPathAndConvertWithAssertFactory() {
// tag::extract-convert-assert-factory[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.extractingPath("$.members")
.convertTo(InstanceOfAssertFactories.list(Member::class.java))
.hasSize(5)
.element(0).satisfies(ThrowingConsumer { member: Member ->
assertThat(member.name).isEqualTo("Homer")
})
// end::extract-convert-assert-factory[]
}
fun assertTheSimpsons() {
// tag::assert-file[]
assertThat(mockMvc.get().uri("/family")).bodyJson()
.isStrictlyEqualTo("sample/simpsons.json")
// end::assert-file[]
}
class FamilyController
@JvmRecord
data class Member(val name: String)
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterintegration
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.*
import org.springframework.test.web.servlet.assertj.MockMvcTester
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
/**
*
* @author Stephane Nicoll
*/
class HotelController {
private val mockMvc = MockMvcTester.of(HotelController())
fun perform() {
// tag::perform[]
// Static import on MockMvcRequestBuilders.get
assertThat(mockMvc.perform(get("/hotels/{id}",42)))
.hasStatusOk()
// end::perform[]
}
fun performWithCustomMatcher() {
// tag::perform[]
// Static import on MockMvcResultMatchers.status
assertThat(mockMvc.get().uri("/hotels/{id}", 42))
.matches(status().isOk())
// end::perform[]
}
class HotelController
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequests
import org.assertj.core.api.Assertions.assertThat
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.assertj.MockMvcTester
class HotelControllerTests {
private val mockMvc = MockMvcTester.of(HotelController())
fun createHotel() {
// tag::post[]
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
. // ...
// end::post[]
hasStatusOk()
}
fun createHotelMultipleAssertions() {
// tag::post-exchange[]
val result = mockMvc.post().uri("/hotels/{id}", 42)
.accept(MediaType.APPLICATION_JSON).exchange()
assertThat(result)
. // ...
// end::post-exchange[]
hasStatusOk()
}
fun queryParameters() {
// tag::query-parameters[]
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
. // ...
//end::query-parameters[]
hasStatusOk()
}
fun parameters() {
// tag::parameters[]
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
. // ...
// end::parameters[]
hasStatusOk()
}
class HotelController
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestsasync
import org.assertj.core.api.Assertions.assertThat
import org.springframework.test.web.servlet.assertj.MockMvcTester
import java.time.Duration
class AsyncControllerTests {
private val mockMvc = MockMvcTester.of(AsyncController())
fun asyncExchangeWithCustomTimeToWait() {
// tag::duration[]
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
. // ...
// end::duration[]
hasStatusOk()
}
class AsyncController
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestsmultipart
import org.assertj.core.api.Assertions.assertThat
import org.springframework.test.web.servlet.assertj.MockMvcTester
import java.nio.charset.StandardCharsets
/**
*
* @author Stephane Nicoll
*/
class MultipartControllerTests {
private val mockMvc = MockMvcTester.of(MultipartController())
fun multiPart() {
// tag::snippet[]
assertThat(mockMvc.post().uri("/upload").multipart()
.file("file1.txt", "Hello".toByteArray(StandardCharsets.UTF_8))
.file("file2.txt", "World".toByteArray(StandardCharsets.UTF_8)))
. // ...
// end::snippet[]
hasStatusOk()
}
class MultipartController
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctesterrequestspaths
import org.assertj.core.api.Assertions.assertThat
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.assertj.MockMvcTester
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder
class HotelControllerTests {
private val mockMvc = MockMvcTester.of(HotelController())
fun contextAndServletPaths() {
// tag::context-servlet-paths[]
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
.contextPath("/app").servletPath("/main"))
. // ...
// end::context-servlet-paths[]
hasStatusOk()
}
fun configureMockMvcTesterWithDefaultSettings() {
// tag::default-customizations[]
val mockMvc =
MockMvcTester.of(listOf(HotelController())) { builder: StandaloneMockMvcBuilder ->
builder.defaultRequest<StandaloneMockMvcBuilder>(
MockMvcRequestBuilders.get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON)
).build()
}
// end::default-customizations[]
mockMvc.toString() // avoid warning
}
class HotelController
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig
import org.springframework.test.web.servlet.assertj.MockMvcTester
import org.springframework.web.context.WebApplicationContext
// tag::snippet[]
@SpringJUnitWebConfig(ApplicationWebConfiguration::class)
class AccountControllerIntegrationTests(@Autowired wac: WebApplicationContext) {
private val mockMvc = MockMvcTester.from(wac)
// ...
}
// end::snippet[]

View File

@ -0,0 +1,29 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup
import org.springframework.test.web.servlet.assertj.MockMvcTester
// tag::snippet[]
class AccountControllerStandaloneTests {
val mockMvc = MockMvcTester.of(AccountController())
// ...
}
// end::snippet[]

View File

@ -0,0 +1,37 @@
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup.converter
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.docs.testing.mockmvc.assertj.mockmvctestersetup.ApplicationWebConfiguration
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig
import org.springframework.test.web.servlet.assertj.MockMvcTester
import org.springframework.web.context.WebApplicationContext
// tag::snippet[]
@SpringJUnitWebConfig(ApplicationWebConfiguration::class)
class AccountControllerIntegrationTests(@Autowired wac: WebApplicationContext) {
private val mockMvc = MockMvcTester.from(wac).withHttpMessageConverters(
listOf(wac.getBean(AbstractJackson2HttpMessageConverter::class.java)))
// ...
}
// end::snippet[]