Polish Spring MVC Test content

master
Rossen Stoyanchev 9 years ago
parent fefc4b478f
commit 9bb29fbc34
  1. 175
      src/asciidoc/testing.adoc

@ -3685,67 +3685,39 @@ instrumenting your test class with a `TestContextManager`. See the source code o
[[spring-mvc-test-framework]]
=== Spring MVC Test Framework
.Standalone project
****
Before inclusion in Spring Framework 3.2, the Spring MVC Test framework had already
existed as a separate project on GitHub where it grew and evolved through actual use,
feedback, and the contribution of many.
The standalone https://github.com/spring-projects/spring-test-mvc[spring-test-mvc project]
is still available on GitHub and can be used in conjunction with Spring Framework 3.1.x.
Applications upgrading to 3.2 or later should replace the `spring-test-mvc` dependency with a
dependency on `spring-test`.
The `spring-test` module uses a different package `org.springframework.test.web` but
otherwise is nearly identical with two exceptions. One is support for features new in
3.2 (e.g. asynchronous web requests). The other relates to the options for creating a
`MockMvc` instance. In Spring Framework 3.2 and later, this can only be done through the
TestContext framework, which provides caching benefits for the loaded configuration.
****
The __Spring MVC Test framework__ provides first class JUnit support for testing client
and server-side Spring MVC code through a fluent API. Typically it loads the actual
Spring configuration through the __TestContext framework__ and always uses the
`DispatcherServlet` to process requests thus approximating full integration tests
without requiring a running Servlet container.
Client-side tests are `RestTemplate`-based and allow tests for code that relies on the
`RestTemplate` without requiring a running server to respond to the requests.
The __Spring MVC Test framework__ provides first class JUnit support for testing
Spring MVC code using a fluent API. It's built on the
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/mock/web/package-summary.html[Servlet API mock objects]
from the `spring-test` module and hence does not require a running Servlet container,
it uses the `DispatcherServlet` thus providing full Spring MVC support, and
may optionally load actual Spring configuration with the __TestContext framework__
in addition to a standalone mode in which controllers may be instantiated manually
and tested 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
require a running server.
[[spring-mvc-test-server]]
==== Server-Side Tests
Before Spring Framework 3.2, the most likely way to test a Spring MVC controller was to
write a unit test that instantiates the controller, injects it with mock or stub
dependencies, and then calls its methods directly, using a `MockHttpServletRequest` and
`MockHttpServletResponse` where necessary.
Although this is pretty easy to do, controllers have many annotations, and much remains
untested. Request mappings, data binding, type conversion, and validation are just a few
examples of what isn't tested. Furthermore, there are other types of annotated methods
such as `@InitBinder`, `@ModelAttribute`, and `@ExceptionHandler` that get invoked as
part of request processing.
The idea behind Spring MVC Test is to be able to re-write those controller tests by
performing actual requests and generating responses, as they would be at runtime, along
the way invoking controllers through the Spring MVC `DispatcherServlet`. Controllers can
still be injected with mock dependencies, so tests can remain focused on the web layer.
Spring MVC Test builds on the familiar "mock" implementations of the Servlet API
It's easy to write a plain JUnit test for a Spring MVC controller. Simply instantiate
the controller, inject it with mock or stub dependencies, and call its methods
passing `MockHttpServletRequest`, `MockHttpServletResponse`, etc. if necessary.
However much remains untested, e.g. 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.
The goal of __Spring MVC Test__ is to provide an effective way of testing controllers
by performing requests and generating responses through the `DispatcherServlet`.
__Spring MVC Test__ builds on the familiar "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 the exception of JSP rendering, which
is not available outside a Servlet container. Furthermore, if you are familiar with how
the `MockHttpServletResponse` works, you'll know that forwards and redirects are not
actually executed. Instead "forwarded" and "redirected" URLs are saved and can be
asserted in tests. This means if you are using JSPs, you can verify the JSP page to
which the request was forwarded.
All other means of rendering including `@ResponseBody` methods and `View` types (besides
JSPs) such as Freemarker, Velocity, Thymeleaf, and others for rendering HTML, JSON, XML,
and so on should work as expected, and the response will contain the generated content.
Below is an example of a test requesting account information in JSON format:
everything should work as it does at runtime with a few notable exceptions as
explained further below. Here is an example of using Spring MVC Test:
[source,java,indent=0]
----
@ -3778,17 +3750,17 @@ Below is an example of a test requesting account information in JSON format:
}
----
The test relies on the `WebApplicationContext` support of the __TestContext framework__.
It loads Spring configuration from an XML configuration file located in the same package
as the test class (also supports JavaConfig) and injects the created
`WebApplicationContext` into the test so a `MockMvc` instance can be created with it.
The above test relies on the `WebApplicationContext` support of the __TestContext framework__
to loads Spring configuration from an XML configuration file located in the same package
as the test class but also supported is Java-based configuration. 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].
The `MockMvc` is then used to perform a request to `"/accounts/1"` and verify the
resulting response status is 200, the response content type is `"application/json"`, and
response content has a JSON property called "name" with the value "Lee". JSON content is
inspected with the help of Jayway's https://github.com/jayway/JsonPath[JsonPath
The `MockMvc` instance is used to perform a request to `"/accounts/1"` and verify the
resulting response has status 200, content type is `"application/json"`, and
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]. There are lots of other options for verifying the result of the performed
request and those will be discussed later.
request that will be discussed below.
[[spring-mvc-test-server-static-imports]]
===== Static Imports
@ -3804,10 +3776,8 @@ completion on static members.
[[spring-mvc-test-server-setup-options]]
===== Setup Options
The goal of server-side test setup is to create an instance of `MockMvc` that can be
used to perform requests. There are two main options.
The first option is to point to Spring MVC configuration through the __TestContext
There are 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 create a `MockMvc`:
@ -3834,11 +3804,10 @@ into the test to use to create a `MockMvc`:
}
----
The second option is to simply register a controller instance without loading any Spring
configuration. Instead basic Spring MVC configuration suitable for testing annotated
controllers is automatically created. The created configuration is comparable to that of
the MVC JavaConfig (and the MVC namespace) and can be customized to a degree through
builder-style methods:
The second is to simply create a controller instance manually without loading Spring
configuration. Instead basic default configuration, roughly comparable to that of
the MVC JavaConfig or the MVC namespace, is automatically created and can be customized
to a degree:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3857,7 +3826,7 @@ builder-style methods:
}
----
Which option should you use?
Which setup option should you use?
The __"webAppContextSetup"__ loads the actual Spring MVC configuration resulting in a
more complete integration test. Since the __TestContext framework__ caches the loaded
@ -3913,8 +3882,7 @@ verify the Spring MVC configuration. Alternatively, you can decide to write all
[[spring-mvc-test-server-performing-requests]]
===== Performing Requests
To perform requests, use the appropriate HTTP method and additional builder-style
methods corresponding to properties of `MockHttpServletRequest`. For example:
It's easy to perform requests using any HTTP method:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3922,8 +3890,9 @@ methods corresponding to properties of `MockHttpServletRequest`. For example:
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
----
In addition to all the HTTP methods, you can also perform file upload requests, which
internally creates an instance of `MockMultipartHttpServletRequest`:
You can also perform file upload requests that internally use
`MockMultipartHttpServletRequest` so that there is no actual parsing of a multipart
request but rather you have to set it up:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3931,7 +3900,7 @@ internally creates an instance of `MockMultipartHttpServletRequest`:
mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));
----
Query string parameters can be specified in the URI template:
You can specify query parameters in URI template style:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3939,7 +3908,7 @@ Query string parameters can be specified in the URI template:
mockMvc.perform(get("/hotels?foo={foo}", "bar"));
----
Or by adding Servlet request parameters:
Or you can add Servlet request parameters representing either query of form parameters:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3947,10 +3916,10 @@ Or by adding Servlet request parameters:
mockMvc.perform(get("/hotels").param("foo", "bar"));
----
If application code relies on Servlet request parameters, and doesn't check the query
string, as is most often the case, then it doesn't matter how parameters are added. Keep
in mind though that parameters provided in the URI template will be decoded while
parameters provided through the `param(...)` method are expected to be decoded.
If application code relies on Servlet request parameters and doesn't check the query
string explicitly (as is most often the case) then it doesn't matter which option you use.
Keep in mind however that query params provided with the URI template will be decoded while
request parameters provided through the `param(...)` method are expected to be decoded.
In most cases it's preferable to leave out the context path and the Servlet path from
the request URI. If you must test with the full request URI, be sure to set the
@ -3963,8 +3932,8 @@ the request URI. If you must test with the full request URI, be sure to set the
----
Looking at the above example, it would be cumbersome to set the contextPath and
servletPath with every performed request. That's why you can define default request
properties when building the `MockMvc`:
servletPath with every performed request. Instead you can set up default request
properties:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3982,15 +3951,15 @@ properties when building the `MockMvc`:
}
----
The above properties will apply to every request performed through the `MockMvc`. If the
same property is also specified on a given request, it will override the default value.
That is why, the HTTP method and URI don't matter, when setting default request
properties, since they must be specified on every request.
The above properties will 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 default request don't matter since they must be
specified on every request.
[[spring-mvc-test-server-defining-expectations]]
===== Defining Expectations
Expectations can be defined by appending one or more `.andExpect(..)` after call to
perform the request:
Expectations can be defined by appending one or more `.andExpect(..)` calls after
performing a request:
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -3998,18 +3967,18 @@ perform the request:
mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
----
`MockMvcResultMatchers.*` defines a number of static members, some of which return types
with additional methods, for asserting the result of the performed request. The
assertions fall in two general categories.
`MockMvcResultMatchers.*` provides a number of expectations some of which are further
nested with more detailed expectations.
The first category of assertions verify properties of the response, i.e the response
status, headers, and content. Those are the most important things to test for.
Expectations fall in two general categories. The first category of assertions verify
properties of the response, i.e the response status, headers, and content. Those
are the most important results to assert.
The second category of assertions go beyond the response, and allow inspecting Spring
MVC specific constructs such as which controller method processed the request, whether
The second category of assertions go beyond the response. They allow inspecting Spring
MVC specific things such as which controller method processed the request, whether
an exception was raised and handled, what the content of the model is, what view was
selected, what flash attributes were added, and so on. It is also possible to verify
Servlet specific constructs such as request and session attributes. The following test
selected, what flash attributes were added, and so on. They also allow inspecting
Servlet specific things such as request and session attributes. The following test
asserts that binding/validation failed:
[source,java,indent=0]
@ -4054,8 +4023,8 @@ after all expectations:
// ...
----
When all tests repeat the same expectations, you can define the common expectations once
when building the `MockMvc`:
When all tests repeat the same expectations you can set up common expectations once
when building the `MockMvc` instance:
[source,java,indent=0]
[subs="verbatim,quotes"]

Loading…
Cancel
Save