Skip to content

Commit d43dba6

Browse files
committed
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
1 parent 7d236e2 commit d43dba6

File tree

54 files changed

+1432
-272
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1432
-272
lines changed

framework-docs/framework-docs.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ dependencies {
4949
api(project(":spring-webmvc"))
5050
api(project(":spring-context-support"))
5151
api(project(":spring-aspects"))
52+
api(project(":spring-test"))
5253
api(project(":spring-websocket"))
5354

5455
api("org.jetbrains.kotlin:kotlin-stdlib")

framework-docs/modules/ROOT/nav.adoc

+24-17
Original file line numberDiff line numberDiff line change
@@ -142,23 +142,30 @@
142142
*** xref:testing/testcontext-framework/support-classes.adoc[]
143143
*** xref:testing/testcontext-framework/aot.adoc[]
144144
** xref:testing/webtestclient.adoc[]
145-
** xref:testing/spring-mvc-test-framework.adoc[]
146-
*** xref:testing/spring-mvc-test-framework/server.adoc[]
147-
*** xref:testing/spring-mvc-test-framework/server-static-imports.adoc[]
148-
*** xref:testing/spring-mvc-test-framework/server-setup-options.adoc[]
149-
*** xref:testing/spring-mvc-test-framework/server-setup-steps.adoc[]
150-
*** xref:testing/spring-mvc-test-framework/server-performing-requests.adoc[]
151-
*** xref:testing/spring-mvc-test-framework/server-defining-expectations.adoc[]
152-
*** xref:testing/spring-mvc-test-framework/async-requests.adoc[]
153-
*** xref:testing/spring-mvc-test-framework/vs-streaming-response.adoc[]
154-
*** xref:testing/spring-mvc-test-framework/server-filters.adoc[]
155-
*** xref:testing/spring-mvc-test-framework/vs-end-to-end-integration-tests.adoc[]
156-
*** xref:testing/spring-mvc-test-framework/server-resources.adoc[]
157-
*** xref:testing/spring-mvc-test-framework/server-htmlunit.adoc[]
158-
**** xref:testing/spring-mvc-test-framework/server-htmlunit/why.adoc[]
159-
**** xref:testing/spring-mvc-test-framework/server-htmlunit/mah.adoc[]
160-
**** xref:testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc[]
161-
**** xref:testing/spring-mvc-test-framework/server-htmlunit/geb.adoc[]
145+
** xref:testing/mockmvc.adoc[]
146+
*** xref:testing/mockmvc/overview.adoc[]
147+
*** xref:testing/mockmvc/setup-options.adoc[]
148+
*** xref:testing/mockmvc/hamcrest.adoc[]
149+
**** xref:testing/mockmvc/hamcrest/static-imports.adoc[]
150+
**** xref:testing/mockmvc/hamcrest/setup.adoc[]
151+
**** xref:testing/mockmvc/hamcrest/setup-steps.adoc[]
152+
**** xref:testing/mockmvc/hamcrest/requests.adoc[]
153+
**** xref:testing/mockmvc/hamcrest/expectations.adoc[]
154+
**** xref:testing/mockmvc/hamcrest/async-requests.adoc[]
155+
**** xref:testing/mockmvc/hamcrest/vs-streaming-response.adoc[]
156+
**** xref:testing/mockmvc/hamcrest/filters.adoc[]
157+
*** xref:testing/mockmvc/assertj.adoc[]
158+
**** xref:testing/mockmvc/assertj/setup.adoc[]
159+
**** xref:testing/mockmvc/assertj/requests.adoc[]
160+
**** xref:testing/mockmvc/assertj/assertions.adoc[]
161+
**** xref:testing/mockmvc/assertj/integration.adoc[]
162+
*** xref:testing/mockmvc/htmlunit.adoc[]
163+
**** xref:testing/mockmvc/htmlunit/why.adoc[]
164+
**** xref:testing/mockmvc/htmlunit/mah.adoc[]
165+
**** xref:testing/mockmvc/htmlunit/webdriver.adoc[]
166+
**** xref:testing/mockmvc/htmlunit/geb.adoc[]
167+
*** xref:testing/mockmvc/vs-end-to-end-integration-tests.adoc[]
168+
*** xref:testing/mockmvc/resources.adoc[]
162169
** xref:testing/spring-mvc-test-client.adoc[]
163170
** xref:testing/appendix.adoc[]
164171
*** xref:testing/annotations.adoc[]

framework-docs/modules/ROOT/pages/testing/integration.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ integration support, and the rest of this chapter then focuses on dedicated topi
3030
* xref:testing/support-jdbc.adoc[JDBC Testing Support]
3131
* xref:testing/testcontext-framework.adoc[Spring TestContext Framework]
3232
* xref:testing/webtestclient.adoc[WebTestClient]
33-
* xref:testing/spring-mvc-test-framework.adoc[MockMvc]
33+
* xref:testing/mockmvc.adoc[MockMvc]
3434
* xref:testing/spring-mvc-test-client.adoc[Testing Client Applications]
3535
* xref:testing/annotations.adoc[Annotations]
3636

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[[mockmvc]]
2+
= MockMvc
3+
:page-section-summary-toc: 1
4+
5+
MockMvc provides support for testing Spring MVC applications. It performs full Spring MVC
6+
request handling but via mock request and response objects instead of a running server.
7+
8+
MockMvc can be used on its own to perform requests and verify responses responses using
9+
Hamcrest, or through `MockMvcTester` that provides a fluent API using AssertJ. Finally,
10+
it can also be used through the xref:testing/webtestclient.adoc[WebTestClient] where
11+
MockMvc is plugged in as the server to handle requests with. The advantage of
12+
`WebTestClient` is the option to work with higher level objects instead of raw data as
13+
well as the ability to switch to full, end-to-end HTTP tests against a live server and
14+
use the same test API.
15+
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[[mockmvc-tester]]
2+
= AssertJ Integration
3+
:page-section-summary-toc: 1
4+
5+
The AssertJ integration builds on top of plain `MockMvc` with several differences:
6+
7+
* There is no need to use static imports as both the requests and assertions can be
8+
crafted using a fluent API.
9+
* Unresolved exceptions are handled consistently so that your tests do not need to
10+
throw (or catch) `Exception`.
11+
* By default, the result to assert is complete whether the processing is asynchronous
12+
or not. In other words, there is no need for special handling for Async requests.
13+
14+
`MockMvcTester` is the entry point for the AssertJ support. It allows to craft the
15+
request and return a result that is AssertJ compatible so that it can be wrapped in
16+
a standard `assertThat()` method.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
[[mockmvc-tester-assertions]]
2+
= Defining Expectations
3+
4+
Assertions work the same way as any AssertJ assertions. The support provides dedicated
5+
assert objects for the various pieces of the `MvcTestResult`, as shown in the following
6+
example:
7+
8+
include-code::./HotelControllerTests[tag=get,indent=0]
9+
10+
If a request fails, the exchange does not throw the exception. Rather, you can assert
11+
that the result of the exchange has failed:
12+
13+
include-code::./HotelControllerTests[tag=failure,indent=0]
14+
15+
The request could also fail unexpectedly, that is the exception thrown by the handler
16+
has not been handled and is thrown as is. You can still use `.hasFailed()` and
17+
`.failure()` but any attempt to access part of the result will throw an exception as
18+
the exchange hasn't completed.
19+
20+
[[mockmvc-tester-assertions-json]]
21+
== JSON Support
22+
23+
The AssertJ support for `MvcTestResult` provides JSON support via `bodyJson()`.
24+
25+
If https://github.com/jayway/JsonPath[JSONPath] is available, you can apply an expression
26+
on the JSON document. The returned value provides convenient methods to return a dedicated
27+
assert object for the various supported JSON data types:
28+
29+
include-code::./FamilyControllerTests[tag=extract-asmap,indent=0]
30+
31+
You can also convert the raw content to any of your data types as long as the message
32+
converter is configured properly:
33+
34+
include-code::./FamilyControllerTests[tag=extract-convert,indent=0]
35+
36+
Converting to a target `Class` provides a generic assert object. For more complex types,
37+
you may want to use `AssertFactory` instead that returns a dedicated assert type, if
38+
possible:
39+
40+
include-code::./FamilyControllerTests[tag=extract-convert-assert-factory,indent=0]
41+
42+
https://jsonassert.skyscreamer.org[JSONAssert] is also supported. The body of the
43+
response can be matched against a `Resource` or a content. If the content ends with
44+
`.json ` we look for a file matching that name on the classpath:
45+
46+
include-code::./FamilyControllerTests[tag=assert-file,indent=0]
47+
48+
If you prefer to use another library, you can provide an implementation of
49+
{spring-framework-api}/test/json/JsonComparator.html[`JsonComparator`].
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[[mockmvc-tester-integration]]
2+
= MockMvc integration
3+
4+
If you want to use the AssertJ support but have invested in the original `MockMvc`
5+
API, `MockMvcTester` offers several ways to integrate with it.
6+
7+
If you have your own `RequestBuilder` implementation, you can trigger the processing
8+
of the request using `perform`. The example below showcases how the query can be
9+
crafted with the original API:
10+
11+
include-code::./HotelControllerTests[tag=perform,indent=0]
12+
13+
Similarly, if you have crafted custom matchers that you use with the `.andExpect` feature
14+
of `MockMvc` you can use them via `.matches`. In the example below, we rewrite the
15+
preceding example to assert the status with the `ResultMatcher` implementation that
16+
`MockMvc` provides:
17+
18+
include-code::./HotelControllerTests[tag=matches,indent=0]
19+
20+
`MockMvc` also defines a `ResultHandler` contract that lets you execute arbitrary actions
21+
on `MvcResult`. If you have implemented this contract you can invoke it using `.apply`.
22+
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
[[mockmvc-tester-requests]]
2+
= Performing Requests
3+
4+
This section shows how to use `MockMvcTester` to perform requests and its integration
5+
with AssertJ to verify responses.
6+
7+
`MockMvcTester` provides a fluent API to compose the request that reuses the same
8+
`MockHttpServletRequestBuilder` as the Hamcrest support, except that there is no need
9+
to import a static method. The builder that is returned is AssertJ-aware so that
10+
wrapping it in the regular `assertThat()` factory method triggers the exchange and
11+
provides access to a dedicated Assert object for `MvcTestResult`.
12+
13+
Here is a simple example that performs a `POST` on `/hotels/42` and configures the
14+
request to specify an `Accept` header:
15+
16+
include-code::./HotelControllerTests[tag=post,indent=0]
17+
18+
AssertJ often consists of multiple `assertThat()` statements to validate the different
19+
parts of the exchange. Rather than having a single statement as in the case above, you
20+
can use `.exchange()` to return a `MvcTestResult` that can be used in multiple
21+
`assertThat` statements:
22+
23+
include-code::./HotelControllerTests[tag=post-exchange,indent=0]
24+
25+
You can specify query parameters in URI template style, as the following example shows:
26+
27+
include-code::./HotelControllerTests[tag=query-parameters,indent=0]
28+
29+
You can also add Servlet request parameters that represent either query or form
30+
parameters, as the following example shows:
31+
32+
include-code::./HotelControllerTests[tag=parameters,indent=0]
33+
34+
If application code relies on Servlet request parameters and does not check the query
35+
string explicitly (as is most often the case), it does not matter which option you use.
36+
Keep in mind, however, that query parameters provided with the URI template are decoded
37+
while request parameters provided through the `param(...)` method are expected to already
38+
be decoded.
39+
40+
41+
[[mockmvc-tester-requests-async]]
42+
== Async
43+
44+
If the processing of the request is done asynchronously, `exchange()` waits for
45+
the completion of the request so that the result to assert is effectively immutable.
46+
The default timeout is 10 seconds but it can be controlled on a request-by-request
47+
basis as shown in the following example:
48+
49+
include-code::./AsyncControllerTests[tag=duration,indent=0]
50+
51+
If you prefer to get the raw result and manage the lifecycle of the asynchronous
52+
request yourself, use `asyncExchange` rather than `exchange`.
53+
54+
[[mockmvc-tester-requests-multipart]]
55+
== Multipart
56+
57+
You can perform file upload requests that internally use
58+
`MockMultipartHttpServletRequest` so that there is no actual parsing of a multipart
59+
request. Rather, you have to set it up to be similar to the following example:
60+
61+
include-code::./MultipartControllerTests[tag=snippet,indent=0]
62+
63+
[[mockmvc-tester-requests-paths]]
64+
== Using Servlet and Context Paths
65+
66+
In most cases, it is preferable to leave the context path and the Servlet path out of the
67+
request URI. If you must test with the full request URI, be sure to set the `contextPath`
68+
and `servletPath` accordingly so that request mappings work, as the following example
69+
shows:
70+
71+
include-code::./HotelControllerTests[tag=context-servlet-paths,indent=0]
72+
73+
In the preceding example, it would be cumbersome to set the `contextPath` and
74+
`servletPath` with every performed request. Instead, you can set up default request
75+
properties, as the following example shows:
76+
77+
include-code::./HotelControllerTests[tag=default-customizations,indent=0]
78+
79+
The preceding properties affect every request performed through the `mockMvc` instance.
80+
If the same property is also specified on a given request, it overrides the default
81+
value. That is why the HTTP method and URI in the default request do not matter, since
82+
they must be specified on every request.
83+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[[mockmvc-tester-setup]]
2+
= Configuring MockMvcTester
3+
4+
`MockMvcTester` can be setup in one of two ways. One is to point directly to the
5+
controllers you want to test and programmatically configure Spring MVC infrastructure.
6+
The second is to point to Spring configuration with Spring MVC and controller
7+
infrastructure in it.
8+
9+
TIP: For a comparison of those two modes, check xref:testing/mockmvc/setup-options.adoc[Setup Options].
10+
11+
To set up `MockMvcTester` for testing a specific controller, use the following:
12+
13+
include-code::./AccountControllerStandaloneTests[tag=snippet,indent=0]
14+
15+
To set up `MockMvcTester` through Spring configuration, use the following:
16+
17+
include-code::./AccountControllerIntegrationTests[tag=snippet,indent=0]
18+
19+
`MockMvcTester` can convert the JSON response body, or the result of a JSONPath expression,
20+
to one of your domain object as long as the relevant `HttpMessageConverter` is registered.
21+
22+
If you use Jackson to serialize content to JSON, the following example registers the
23+
converter:
24+
25+
include-code::./converter/AccountControllerIntegrationTests[tag=snippet,indent=0]
26+
27+
NOTE: The above assumes the converter has been registered as a Bean.
28+
29+
Finally, if you have a `MockMvc` instance handy, you can create a `MockMvcTester` by
30+
providing the `MockMvc` instance to use using the `create` factory method.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[[mockmvc-server]]
2+
= Hamcrest Integration
3+
:page-section-summary-toc: 1
4+
5+
Plain `MockMvc` provides an API to build the request using a builder-style approach
6+
that can be initiated with static imports. Hamcrest is used to define expectations and
7+
it provides many out-of-the-box options for common needs.

framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/async-requests.adoc renamed to framework-docs/modules/ROOT/pages/testing/mockmvc/hamcrest/async-requests.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[spring-mvc-test-async-requests]]
1+
[[mockmvc-async-requests]]
22
= Async Requests
33

44
This section shows how to use MockMvc on its own to test asynchronous request handling.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[spring-mvc-test-server-defining-expectations]]
1+
[[mockmvc-server-defining-expectations]]
22
= Defining Expectations
33

44
You can define expectations by appending one or more `andExpect(..)` calls after
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[spring-mvc-test-server-filters]]
1+
[[mockmvc-server-filters]]
22
= Filter Registrations
33
:page-section-summary-toc: 1
44

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[spring-mvc-test-server-performing-requests]]
1+
[[mockmvc-server-performing-requests]]
22
= Performing Requests
33

44
This section shows how to use MockMvc on its own to perform requests and verify responses.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[spring-mvc-test-server-setup-steps]]
1+
[[mockmvc-server-setup-steps]]
22
= Setup Features
33

44
No matter which MockMvc builder you use, all `MockMvcBuilder` implementations provide

0 commit comments

Comments
 (0)