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 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 + 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 Expectations Expectations 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 Registrations When 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.
-
-