diff --git a/src/reference/docbook/testing.xml b/src/reference/docbook/testing.xml
index 93ffe9e8b6..1ff24f9baa 100644
--- a/src/reference/docbook/testing.xml
+++ b/src/reference/docbook/testing.xml
@@ -2406,88 +2406,90 @@ public class SimpleTest {
Standalone projectBefore 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
+ 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
- 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 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. async web requests).
- The other relates to the options
- for creating a MockMvc instance. In Spring
- Framework 3.2, this can only be done through the TestContext framework,
- which provides caching benefits for the loaded configuration.
+ The standalone 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
+ 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. async web requests). The other relates to
+ the options for creating a MockMvc instance. In
+ Spring Framework 3.2, 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.
+ 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.
-
+ 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.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
+ 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 not tested. 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,
+
+ 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.
+ @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.
+ 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 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 using JSPs, you can verify the JSP page
- the request was forwarded to.
+ 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.
-
+ 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:
+ Below is an example of a test requesting account information in
+ JSON format:
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -2515,59 +2517,56 @@ public class ExampleTests {
}
- The test relies on the WebApplicationContext
- support of the TestContext framework. It loads Spring configuration from
- an XML config file located in the same
- package as the test class (also supports Java config) and injects
- the created WebApplicationContext
- into the test so a MockMvc instance can be
- created with it.
+ The test relies on the
+ WebApplicationContext support of the
+ TestContext framework. It loads Spring
+ configuration from an XML config file located in the same package as
+ the test class (also supports Java config) and injects the created
+ WebApplicationContext into the test so
+ a MockMvc instance can be created with
+ it.
- The MockMvc is then
- used to perform a request to "/accounts/1"
- and verify the resulting
+ 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
- JsonPath project.
- There are lots of other options for verifying the
- result of the performed request and those will be discussed later.
+ "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 JsonPath project.
+ There are lots of other options for verifying the result of the
+ performed request and those will be discussed later.Static Imports
- The fluent API in the example above requires a few static imports
- such as MockMvcRequestBuilders.*,
+ The fluent API in the example above requires a few static
+ imports such as MockMvcRequestBuilders.*,
MockMvcResultMatchers.*, and
- MockMvcBuilders.*. An easy way to find
- these classes is to search for types matching
- "MockMvc*".
- If using Eclipse, be sure to add them as
- "favorite static members" in the Eclipse preferences under
- Java -> Editor -> Content Assist -> Favorites.
- That will allow use of content assist after typing
- the first character of the static method name.
- Other IDEs (e.g. IntelliJ) may not require any additional
- configuration. Just check the support for code completion
- on static members.
-
+ MockMvcBuilders.*. An easy way to find these
+ classes is to search for types matching
+ "MockMvc*". If using Eclipse, be sure to add
+ them as "favorite static members" in the Eclipse preferences under
+ Java -> Editor -> Content Assist ->
+ Favorites. That will allow use of content assist after
+ typing the first character of the static method name. Other IDEs
+ (e.g. IntelliJ) may not require any additional configuration. Just
+ check the support for code completion on static members.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 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 framework,
- which loads the Spring configuration and injects a
- WebApplicationContext into the
- test to use to create a MockMvc:
+ through the TestContext framework, which loads
+ the Spring configuration and injects a
+ WebApplicationContext into the test
+ to use to create a MockMvc:
-@RunWith(SpringJUnit4ClassRunner.class)
+ @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("my-servlet-context.xml")
public class MyWebTests {
@@ -2586,15 +2585,14 @@ public class MyWebTests {
}
- 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 Java config
- (and the MVC namespace) and can be customized to a degree
- through builder-style methods:
+ 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 Java config (and the MVC namespace) and can be
+ customized to a degree through builder-style methods:
-public class MyWebTests {
+ public class MyWebTests {
private MockMvc mockMvc;
@@ -2609,26 +2607,25 @@ public class MyWebTests {
Which 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
- Spring configuration, it helps to keep tests running fast
+ The "webAppContextSetup" loads the actual
+ Spring MVC configuration resulting in a more complete integration
+ test. Since the TestContext framework caches
+ the loaded Spring configuration, it helps to keep tests running fast
even as more tests get added. Furthermore, you can inject mock
- services into controllers through Spring configuration,
- in order to remain focused on testing the web layer.
- Here is an example of declaring a mock service with Mockito:
+ services into controllers through Spring configuration, in order to
+ remain focused on testing the web layer. Here is an example of
+ declaring a mock service with Mockito:
-
+
<bean id="accountService" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.example.AccountService"/>
</bean>
- Then you can inject the mock service into the test
- in order set up and verify expectations:
+ Then you can inject the mock service into the test in order
+ set up and verify expectations:
-@RunWith(SpringJUnit4ClassRunner.class)
+ @RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("test-servlet-context.xml")
public class AccountTests {
@@ -2645,33 +2642,32 @@ public class AccountTests {
}
- The "standaloneSetup" on the other
- hand is a little closer to a unit test. It tests one controller at a time,
- the controller can be injected with mock dependencies manually,
- and it doesn't involve loading Spring configuration.
- Such tests are more focused in 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 some
+ The "standaloneSetup" on the other hand
+ is a little closer to a unit test. It tests one controller at a
+ time, the controller can be injected with mock dependencies
+ manually, and it doesn't involve loading Spring configuration. Such
+ tests are more focused in 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 some
behavior or to debug an issue.
- Just like with integration vs unit testing, there is no right or
- wrong answer. Using the "standaloneSetup" does imply the
- need for some additional "webAppContextSetup" tests to verify the
- Spring MVC configuration. Alternatively, you can decide write all
- tests with "webAppContextSetup" and always test against actual
- Spring MVC configuration.
+ Just like with integration vs unit testing, there is no right
+ or wrong answer. Using the "standaloneSetup" does imply the need for
+ some additional "webAppContextSetup" tests to verify the Spring MVC
+ configuration. Alternatively, you can decide write all tests with
+ "webAppContextSetup" and always test against actual Spring MVC
+ configuration.Performing Requests
- To perform requests, use the appropriate HTTP
- method and additional builder-style methods corresponding
- to properties of MockHttpServletRequest.
- For example:
+ To perform requests, use the appropriate HTTP method and
+ additional builder-style methods corresponding to properties of
+ MockHttpServletRequest. For example:
-
+
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
@@ -2679,44 +2675,45 @@ mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
upload requests, which 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:
+ Query string parameters can be specified in the URI
+ template:
-
+
mockMvc.perform(get("/hotels?foo={foo}", "bar"));
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.
+ 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.
- 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 contextPath and servletPath
+ 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 contextPath and servletPath
accordingly so that request mappings will work:
-
+
mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
Looking at the above example, it would be cumbersome to set
- the contextPath and servletPath with every peformed request.
- That's why you can define default request
- properties when building the MockMvc:
+ the contextPath and servletPath with every performed request. That's
+ why you can define default request properties when building the
+ MockMvc:
-
+
public class MyWebTests {
private MockMvc mockMvc;
@@ -2731,43 +2728,44 @@ public class MyWebTests {
}
- 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 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.Defining ExpectationsExpectations can be defined by appending one or more
- .andExpect(..) after call to perform the request:
+ .andExpect(..) after call to 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
+ 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.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.
+ response, i.e the response status, headers, and content. Those are
+ the most important things to test for.
- 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 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 asserts that binding/validation failed:
-
+ 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 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 asserts that
+ binding/validation failed:
-
+
mockMvc.perform(post("/persons"))
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
@@ -2776,7 +2774,7 @@ mockMvc.perform(post("/persons"))
Many times when writing tests, it's useful to dump the result
of the performed request. This can be done as follows:
-
+
mockMvc.perform(post("/persons"))
.andDo(print())
.andExpect(status().isOk())
@@ -2785,14 +2783,16 @@ mockMvc.perform(post("/persons"))
where print() is a static import from
MockMvcResultHandlers. As long as request processing
- does cause an unhandled exception, the print()
- method will print all the available result data to System.out.
+ does cause an unhandled exception, the print() method
+ will print all the available result data to
+ System.out.
- In some cases, you may want to get direct access to the result and
- verify something that cannot be verified otherwise. This can be done by
- appending .andReturn() at the end after all expectations:
+ In some cases, you may want to get direct access to the result
+ and verify something that cannot be verified otherwise. This can be
+ done by appending .andReturn() at the end after all
+ expectations:
-
+
MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...
@@ -2801,75 +2801,76 @@ MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk(
the common expectations once when building the
MockMvc:
-
+
standaloneSetup(new SimpleController())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
- Note that the expectation is always applied
- and cannot be overridden without creating a separate
- MockMvc instance.
+ Note that the expectation is always
+ applied and cannot be overridden without creating a separate
+ MockMvc instance.
- When JSON response content contains hypermedia links created with
- Spring HATEOAS,
- the resulting links can be verified:
+ When JSON response content contains hypermedia links created
+ with Spring
+ HATEOAS, the resulting links can be verified:
-
+
mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));
- When XML response content contains hypermedia links created with
- Spring HATEOAS,
- the resulting links can be verified:
+ When XML response content contains hypermedia links created
+ with Spring
+ HATEOAS, the resulting links can be verified:
-
+
Map<String, String> ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
-
Filter RegistrationsWhen setting up a MockMvc, you can
- register one or more Filter instances:
+ register one or more Filter
+ instances:
-
+
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
Registered filters will be invoked through
MockFilterChain from
- spring-test and the last filter will delegates to
- the DispatcherServlet.
-
+ spring-test and the last filter will delegates
+ to the DispatcherServlet.
Further Server-Side Test Examples
- The framework's own tests include
- many sample tests
- intended to demonstrate how to use Spring MVC Test.
- Browse these examples for further ideas. Also the
- spring-mvc-showcase
- has full test coverage based on Spring MVC Test.
+ The framework's own tests include many
+ sample tests intended to demonstrate how to use Spring MVC
+ Test. Browse these examples for further ideas. Also the spring-mvc-showcase
+ has full test coverage based on Spring MVC Test.
-
Client-Side REST Tests
- Client-side tests are for code using the RestTemplate.
- The goal is to define expected requests and provide "stub" responses:
+ Client-side tests are for code using the
+ RestTemplate. The goal is to define expected
+ requests and provide "stub" responses:
-
+
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
@@ -2880,48 +2881,45 @@ mockServer.expect(requestTo("/greeting")).andRespond(withSuccess("Hello world",
mockServer.verify();
- In the above example, MockRestServiceServer --
- the central class for client-side REST tests -- configures the
+ In the above example,
+ MockRestServiceServer -- the central class for
+ client-side REST tests -- configures the
RestTemplate with a custom
ClientHttpRequestFactory that asserts
- actual requests against expectations and returns "stub" responses.
- In this case we expect a single request to "/greeting" and want to return
+ actual requests against expectations and returns "stub" responses. In
+ this case we expect a single request to "/greeting" and want to return
a 200 response with "text/plain" content. We could define as many
additional requests and stub responses as necessary.
- Once expected requests and stub
- responses have been defined, the RestTemplate can
- be used in client-side code as usual. At the end of the tests
- mockServer.verify()
- can be used to verify that all expected requests were performed.
+ Once expected requests and stub responses have been defined, the
+ RestTemplate can be used in client-side code as
+ usual. At the end of the tests mockServer.verify() can be
+ used to verify that all expected requests were performed.Static Imports
- Just like with server-side tests, the fluent API for client-side tests
- requires a few static imports. Those are easy to find by searching
- "MockRest*". Eclipse users should add
- "MockRestRequestMatchers.*" and
- "MockRestResponseCreators.*"
- as "favorite static members" in the Eclipse preferences under
- Java -> Editor -> Content Assist -> Favorites.
- That allows using content assist after typing
- the first character of the static method name.
- Other IDEs (e.g. IntelliJ) may not require any additional
- configuration. Just check the support for code completion
+ Just like with server-side tests, the fluent API for
+ client-side tests requires a few static imports. Those are easy to
+ find by searching "MockRest*". Eclipse users
+ should add "MockRestRequestMatchers.*" and
+ "MockRestResponseCreators.*" as "favorite
+ static members" in the Eclipse preferences under Java
+ -> Editor -> Content Assist -> Favorites. That
+ allows using content assist after typing the first character of the
+ static method name. Other IDEs (e.g. IntelliJ) may not require any
+ additional configuration. Just check the support for code completion
on static members.Further Examples of Client-side REST Tests
- Spring MVC Test's own tests include
- example tests
- of client-side REST tests.
+ Spring MVC Test's own tests include example
+ tests of client-side REST tests.
-
-