Browse Source

Updates to Web testing sections of reference docs

Closes gh-19647
pull/25684/head
Rossen Stoyanchev 6 years ago
parent
commit
c6b87b3ef4
  1. 150
      src/docs/asciidoc/testing-webtestclient.adoc
  2. 234
      src/docs/asciidoc/testing.adoc

150
src/docs/asciidoc/testing-webtestclient.adoc

@ -3,11 +3,11 @@ @@ -3,11 +3,11 @@
:doc-root: https://docs.spring.io
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
`WebTestClient` is a thin shell around <<web-reactive.adoc#webflux-client, WebClient>>,
using it to perform requests and exposing a dedicated, fluent API for verifying responses.
`WebTestClient` binds to a WebFlux application by using a
<<testing.adoc#mock-objects-web-reactive, mock request and response>>, or it can test any
web server over an HTTP connection.
`WebTestClient` is an HTTP client designed for testing server applications. It wraps
Spring's <<web-reactive.adoc#webflux-client, WebClient>> and uses it to perform requests
but exposes a testing facade for verifying responses. `WebTestClient` can be used to
perform end-to-end HTTP tests. It can also be used to test Spring MVC and Spring WebFlux
applications without a running server via mock server request and response objects.
TIP: Kotlin users: See <<languages.adoc#kotlin-webtestclient-issue, this section>>
related to use of the `WebTestClient`.
@ -18,65 +18,61 @@ related to use of the `WebTestClient`. @@ -18,65 +18,61 @@ related to use of the `WebTestClient`.
[[webtestclient-setup]]
== Setup
To create a `WebTestClient` you must choose one of several server setup options.
Effectively you're either configuring the WebFlux application to bind to or using
a URL to connect to a running server.
To set up a `WebTestClient` you need to choose a server setup to bind to. This can be one
of several mock server setup choices or a connection to a live server.
[[webtestclient-controller-config]]
=== Bind to Controller
The following example shows how to create a server setup to test one `@Controller` at a time:
This setup allows you to test specific controller(s) via mock request and response objects,
without a running server.
For WebFlux applications, use the below which loads the
<<web-reactive.adoc#webflux-config, WebFlux Java configuration>> and registers the given
controller(s) to handle requests with:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
client = WebTestClient.bindToController(new TestController()).build();
WebTestClient client =
WebTestClient.bindToController(new TestController()).build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
client = WebTestClient.bindToController(TestController()).build()
val client = WebTestClient.bindToController(TestController()).build()
----
The preceding example loads the <<web-reactive.adoc#webflux-config, WebFlux Java configuration>>
and registers the given controller. The resulting WebFlux application is tested
without an HTTP server by using mock request and response objects. There are more methods
on the builder to customize the default WebFlux Java configuration.
[[webtestclient-fn-config]]
=== Bind to Router Function
The following example shows how to set up a server from a
<<web-reactive.adoc#webflux-fn, RouterFunction>>:
For Spring MVC, use the below which loads infrastructure equivalent to the
<<web.adoc#mvc-config, WebMvc Java config>> and registers the given controller(s) to
handle requests with via <<testing.adoc#spring-mvc-test-framework, MockMvc>>:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RouterFunction<?> route = ...
client = WebTestClient.bindToRouterFunction(route).build();
WebTestClient client =
MockMvcWebTestClient.bindToController(new TestController()).build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val route: RouterFunction<*> = ...
val client = WebTestClient.bindToRouterFunction(route).build()
val client = MockMvcWebTestClient.bindToController(TestController()).build()
----
Internally, the configuration is passed to `RouterFunctions.toWebHandler`.
The resulting WebFlux application is tested without an HTTP server by using mock
request and response objects.
[[webtestclient-context-config]]
=== Bind to `ApplicationContext`
The following example shows how to set up a server from the Spring configuration of your
application or some subset of it:
This setup allows you to point to Spring configuration with Spring MVC or Spring WebFlux
infrastructure and controller declarations which is then exercised via mock request and
response objects, without a running server.
For WebFlux, use the below in which the given Spring `ApplicationContext` is passed to
`WebHttpHandlerBuilder` to create the
<<web-reactive.adoc#webflux-web-handler-api, WebHandler chain>> to handle requests with:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@ -114,10 +110,88 @@ application or some subset of it: @@ -114,10 +110,88 @@ application or some subset of it:
<2> Inject the configuration
<3> Create the `WebTestClient`
Internally, the configuration is passed to `WebHttpHandlerBuilder` to set up the request
processing chain. See <<web-reactive.adoc#webflux-web-handler-api, WebHandler API>> for
more details. The resulting WebFlux application is tested without an HTTP server by
using mock request and response objects.
For Spring MVC, use the below in which the given Spring `ApplicationContext` is passed
to `MockMvcBuilders#webAppContextSetup` to create a
<<testing.adoc#spring-mvc-test-framework, MockMvc>> to handle requests with:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration("classpath:META-INF/web-resources") // <1>
@ContextHierarchy({
@ContextConfiguration(classes = RootConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class MyTests {
@Autowired
private WebApplicationContext wac; // <2>
WebTestClient client;
@BeforeEach
void setUp() {
client = MockMvcWebTestClient.bindToApplicationContext(this.wac).build(); // <3>
}
}
----
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration("classpath:META-INF/web-resources") // <1>
@ContextHierarchy({
@ContextConfiguration(classes = RootConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class MyTests {
@Autowired
lateinit var wac: WebApplicationContext; // <2>
lateinit var client: WebTestClient
@BeforeEach
fun setUp() { // <2>
client = WebTestClient.bindToApplicationContext(context).build() // <3>
}
}
----
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
[[webtestclient-fn-config]]
=== Bind to Router Function
This setup allows you to test <<web-reactive.adoc#webflux-fn, functional endpoints>>
via mock request and response objects, without a running server.
For WebFlux, use the below which delegates to `RouterFunctions.toWebHandler` to create a
server setup to handle requests with:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
RouterFunction<?> route = ...
client = WebTestClient.bindToRouterFunction(route).build();
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val route: RouterFunction<*> = ...
val client = WebTestClient.bindToRouterFunction(route).build()
----
For Spring MVC there is currently no options to test
<<web.adoc#webmvc-fn, WebMvc functional endpoints>>.
@ -140,7 +214,7 @@ The following server setup option lets you connect to a running server: @@ -140,7 +214,7 @@ The following server setup option lets you connect to a running server:
[[webtestclient-client-config]]
=== Client Builder
=== Client Config
In addition to the server setup options described earlier, you can also configure client
options, including base URL, default headers, client filters, and others. These options

234
src/docs/asciidoc/testing.adoc

@ -6488,151 +6488,83 @@ of `AbstractTestNGSpringContextTests` for an example of how to instrument your t @@ -6488,151 +6488,83 @@ of `AbstractTestNGSpringContextTests` for an example of how to instrument your t
[[spring-mvc-test-framework]]
=== Spring MVC Test Framework
The Spring MVC Test framework provides first class support for testing Spring MVC code
with a fluent API that you can use with JUnit, TestNG, or any other testing framework. It
is built on the {api-spring-framework}/mock/web/package-summary.html[Servlet API mock objects]
from the `spring-test` module and, hence, does not use a running Servlet container. It
uses the `DispatcherServlet` to provide full Spring MVC runtime behavior and provides
support for loading actual Spring configuration with the TestContext framework in
addition to a standalone mode, in which you can manually instantiate controllers and test
them one at a time.
Spring MVC Test also provides client-side support for testing code that uses the
`RestTemplate`. Client-side tests mock the server responses and also do not use a running
server.
TIP: Spring Boot provides an option to write full, end-to-end integration tests that
include a running server. If this is your goal, see the
{doc-spring-boot}/html/spring-boot-features.html#boot-features-testing[Spring Boot Reference Guide].
For more information on the differences between out-of-container and end-to-end
integration tests, see <<spring-mvc-test-vs-end-to-end-integration-tests>>.
include::testing-webtestclient.adoc[leveloffset=+2]
[[spring-mvc-test-server]]
==== Server-Side Tests
You can write a plain unit test for a Spring MVC controller by using JUnit or TestNG. To
do so, instantiate the controller, inject it with mocked or stubbed dependencies, and
call its methods (passing `MockHttpServletRequest`, `MockHttpServletResponse`, and
others, as necessary). However, when writing such a unit test, much remains untested: for
example, request mappings, data binding, type conversion, validation, and much more.
Furthermore, other controller methods such as `@InitBinder`, `@ModelAttribute`, and
`@ExceptionHandler` may also be invoked as part of the request processing lifecycle.
[[spring-mvc-test-framework]]
=== MockMvc
The goal of Spring MVC Test is to provide an effective way to test controllers by
performing requests and generating responses through the actual `DispatcherServlet`.
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.
Spring MVC Test builds on the familiar <<mock-objects-servlet, "`mock`" implementations of
the Servlet API>> available in the `spring-test` module. This allows performing requests
and generating responses without the need for running in a Servlet container. For the
most part, everything should work as it does at runtime with a few notable exceptions, as
explained in <<spring-mvc-test-vs-end-to-end-integration-tests>>. The following JUnit
Jupiter-based example uses Spring MVC Test:
MockMvc can be used on its own to perform requests and verify responses. It can also be
used through the <<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.
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringJUnitWebConfig(locations = "test-servlet-context.xml")
class ExampleTests {
[[spring-mvc-test-server]]
==== Overview
MockMvc mockMvc;
You can write plain unit tests for Spring MVC by instantiating a controller, injecting it
with dependencies, and calling its methods. However such tests do not verify request
mappings, data binding, message conversion, type conversion, validation, and nor
do they involve any of the supporting `@InitBinder`, `@ModelAttribute`, or
`@ExceptionHandler` methods.
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
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 `DispacherServlet` and passing
<<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.
@Test
void getAccount() throws Exception {
this.mockMvc.perform(get("/accounts/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.name").value("Lee"));
}
}
----
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.test.web.servlet.get
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 <<webtestclient>> API with MockMvc plugged in as the server to handle requests
with.
@SpringJUnitWebConfig(locations = ["test-servlet-context.xml"])
class ExampleTests {
lateinit var mockMvc: MockMvc
[[spring-mvc-test-server-static-imports]]
===== Static Imports
@BeforeEach
fun setup(wac: WebApplicationContext) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
}
When using MockMvc directly to perform requests, you'll need static imports for:
@Test
fun getAccount() {
mockMvc.get("/accounts/1") {
accept = MediaType.APPLICATION_JSON
}.andExpect {
status { isOk }
content { contentType(MediaType.APPLICATION_JSON) }
jsonPath("$.name") { value("Lee") }
}
}
}
----
- `MockMvcBuilders.{asterisk}`
- `MockMvcRequestBuilders.{asterisk}`
- `MockMvcResultMatchers.{asterisk}`
- `MockMvcResultHandlers.{asterisk}`
NOTE: A dedicated <<languages.adoc#mockmvc-dsl, MockMvc DSL>> is available in Kotlin
An easy way to remember that is search for `MockMvc*`. If using Eclipse be sure to also
add the above as "`favorite static members`" in the Eclipse preferences.
The preceding test relies on the `WebApplicationContext` support of the TestContext
framework to load Spring configuration from an XML configuration file located in the same
package as the test class, but Java-based and Groovy-based configuration are also
supported. See these
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/context[sample tests].
When using MockMvc through the <<webtestclient>> you do not need static imports.
The `WebTestClient` provides a fluent API without static imports.
The `MockMvc` instance is used to perform a `GET` request to `/accounts/1` and verify
that the resulting response has status 200, the content type is `application/json`, and
the response body has a JSON property called `name` with the value `Lee`. The `jsonPath`
syntax is supported through the Jayway https://github.com/jayway/JsonPath[JsonPath
project]. Many other options for verifying the result of the performed request are
discussed later in this document.
[[spring-mvc-test-server-static-imports]]
===== Static Imports
The fluent API in the example from the <<spring-mvc-test-server, preceding section>>
requires a few static imports, such as `MockMvcRequestBuilders.{asterisk}`,
`MockMvcResultMatchers.{asterisk}`, and `MockMvcBuilders.{asterisk}`. An easy way to find
these classes is to search for types that match `MockMvc*`. If you use Eclipse or the
https://spring.io/tools[Spring Tools for Eclipse], be sure to add them as "`favorite static members`" in
the Eclipse preferences under Java -> Editor -> Content Assist -> Favorites. Doing so
lets you use content assist after typing the first character of the static method name.
Other IDEs (such as IntelliJ) may not require any additional configuration. Check the
support for code completion on static members.
[[spring-mvc-test-server-setup-options]]
===== Setup Choices
You have two main options for creating an instance of `MockMvc`. The first is to load
Spring MVC configuration through the TestContext framework, which loads the Spring
configuration and injects a `WebApplicationContext` into the test to use to build a
`MockMvc` instance. The following example shows how to do so:
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:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
@ -6643,14 +6575,13 @@ configuration and injects a `WebApplicationContext` into the test to use to buil @@ -6643,14 +6575,13 @@ configuration and injects a `WebApplicationContext` into the test to use to buil
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(locations = ["my-servlet-context.xml"])
class MyWebTests {
lateinit var mockMvc: MockMvc
lateinit var mockMvc : MockMvc
@BeforeEach
fun setup(wac: WebApplicationContext) {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
fun setup() {
mockMvc = MockMvcBuilders.standaloneSetup(AccountController()).build()
}
// ...
@ -6658,21 +6589,23 @@ configuration and injects a `WebApplicationContext` into the test to use to buil @@ -6658,21 +6589,23 @@ configuration and injects a `WebApplicationContext` into the test to use to buil
}
----
Your second option is to manually create a controller instance without loading Spring
configuration. Instead, basic default configuration, roughly comparable to that of the
MVC JavaConfig or the MVC namespace, is automatically created. You can customize it to a
degree. The following example shows how to do so:
Or you can also use this setup when testing through the
<<webtestclient-controller-config, WebTestClient>> which delegates to the same builder
as shown above.
To set up MockMvc through Spring configuration, use the following:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@SpringJUnitWebConfig(locations = "my-servlet-context.xml")
class MyWebTests {
MockMvc mockMvc;
@BeforeEach
void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
void setup(WebApplicationContext wac) {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
// ...
@ -6683,13 +6616,14 @@ degree. The following example shows how to do so: @@ -6683,13 +6616,14 @@ degree. The following example shows how to do so:
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitWebConfig(locations = ["my-servlet-context.xml"])
class MyWebTests {
lateinit var mockMvc : MockMvc
lateinit var mockMvc: MockMvc
@BeforeEach
fun setup() {
mockMvc = MockMvcBuilders.standaloneSetup(AccountController()).build()
fun setup(wac: WebApplicationContext) {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
}
// ...
@ -6697,6 +6631,12 @@ degree. The following example shows how to do so: @@ -6697,6 +6631,12 @@ degree. The following example shows how to do so:
}
----
Or you can also use this setup when testing through the
<<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
@ -6826,7 +6766,11 @@ for a list of all MockMvc builder features or use the IDE to explore the availab @@ -6826,7 +6766,11 @@ for a list of all MockMvc builder features or use the IDE to explore the availab
[[spring-mvc-test-server-performing-requests]]
===== Performing Requests
You can perform requests that use any HTTP method, as the following example shows:
This section shows how to use MockMvc on its own to perform requests and verify responses.
If using MockMvc through the `WebTestClient` please see the corresponding section on
<<webtestclient-tests>> instead.
To perform requests that use any HTTP method, as the following example shows:
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
@ -7137,6 +7081,11 @@ resulting links by using XPath expressions: @@ -7137,6 +7081,11 @@ resulting links by using XPath expressions:
[[spring-mvc-test-async-requests]]
===== Async Requests
This section shows how to use MockMvc on its own to test asynchronous request handling.
If using MockMvc through the <<webtestclient>>, there is nothing special to do to make
asynchronous requests work as the `WebTestClient` automatically does what is described
in this section.
Servlet 3.0 asynchronous requests,
<<web.adoc#mvc-ann-async,supported in Spring MVC>>, work by exiting the Servlet container
thread and allowing the application to compute the response asynchronously, after which
@ -7200,10 +7149,8 @@ or reactive type such as Reactor `Mono`: @@ -7200,10 +7149,8 @@ or reactive type such as Reactor `Mono`:
===== Streaming Responses
There are no options built into Spring MVC Test for container-less testing of streaming
responses. Applications that make use of
<<web.adoc#mvc-ann-async-http-streaming,Spring MVC streaming>> options can use the
<<testing.adoc#webtestclient-stream,WebTestClient>> to perform end-to-end, integration
tests against a running server. This is also supported in Spring Boot where you can
responses. However you can test streaming requests through the <<WebTestClient>>.
This is also supported in Spring Boot where you can
{doc-spring-boot}/html/spring-boot-features.html#boot-features-testing-spring-boot-applications-testing-with-running-server[test a running server]
with `WebTestClient`. One extra advantage is the ability to use the `StepVerifier` from
project Reactor that allows declaring expectations on a stream of data.
@ -7231,9 +7178,9 @@ last filter delegates to the `DispatcherServlet`. @@ -7231,9 +7178,9 @@ last filter delegates to the `DispatcherServlet`.
[[spring-mvc-test-vs-end-to-end-integration-tests]]
===== Spring MVC Test vs End-to-End Tests
===== MockMvc vs End-to-End Tests
Spring MVC Test is built on Servlet API mock implementations from the
MockMVc is built on Servlet API mock implementations from the
`spring-test` module and does not rely on a running container. Therefore, there are
some differences when compared to full end-to-end integration tests with an actual
client and a live server running.
@ -7280,11 +7227,10 @@ of testing even within the same project. @@ -7280,11 +7227,10 @@ of testing even within the same project.
===== Further Examples
The framework's own tests include
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples[many
sample tests] intended to show how to use Spring MVC Test. You can browse these examples
for further ideas. Also, the
https://github.com/spring-projects/spring-mvc-showcase[`spring-mvc-showcase`] project has
full test coverage based on Spring MVC Test.
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples[
many sample tests] intended to show how to use MockMvc on its own or through the
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client[
WebTestClient]. Browse these examples for further ideas.
[[spring-mvc-test-server-htmlunit]]
@ -8359,7 +8305,7 @@ http://www.gebish.org/manual/current/[The Book of Geb] user's manual. @@ -8359,7 +8305,7 @@ http://www.gebish.org/manual/current/[The Book of Geb] user's manual.
[[spring-mvc-test-client]]
==== Client-Side REST Tests
=== Testing Client Applications
You can use client-side tests to test code that internally uses the `RestTemplate`. The
idea is to declare expected requests and to provide "`stub`" responses so that you can
@ -8478,7 +8424,7 @@ logic but without running a server. The following example shows how to do so: @@ -8478,7 +8424,7 @@ logic but without running a server. The following example shows how to do so:
----
[[spring-mvc-test-client-static-imports]]
===== Static Imports
==== Static Imports
As with server-side tests, the fluent API for client-side tests requires a few static
imports. Those are easy to find by searching for `MockRest*`. Eclipse users should add
@ -8489,14 +8435,12 @@ the static method name. Other IDEs (such IntelliJ) may not require any additiona @@ -8489,14 +8435,12 @@ the static method name. Other IDEs (such IntelliJ) may not require any additiona
configuration. Check for the support for code completion on static members.
[[spring-mvc-test-client-resources]]
===== Further Examples of Client-side REST Tests
==== Further Examples of Client-side REST Tests
Spring MVC Test's own tests include
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/client/samples[example
tests] of client-side REST tests.
include::testing-webtestclient.adoc[leveloffset=+2]
[[testing-resources]]

Loading…
Cancel
Save