Spring Framework 3.2 RC1: Spring MVC Test Framework |

The final Spring Framework reference documentation contains guidance on migration as well as a complete section on Spring MVC Test.
Last week Juergen Hoeller announced the release of Spring Framework 3.2 RC1 and Sam Brannen discussed exciting additions in its spring-test module such as support for WebApplicationContext's and upcoming plans for loading a hierarchy of contexts. Today I will continue this subject and describe another exciting spring-test addition. In 3.2 RC1 we've added first class support for testing Spring MVC applications both client-side and server-side.
Background
The Spring MVC Test framework discussed here originates from a standalone project on Github, where features evolved for over a year with continuous feedback from many users. Thanks to all the early adopters, everyone who contributed, reported issues, commented, and everyone who blogged or spoke about it.
As of Spring 3.2 RC1, the code from the standalone project has been added to the Spring Framework and is available in the spring-test module, under slightly modified package names, and with support for 3.2 specific features such as async requests and others. The standalone project will continue to exist for applications testing against Spring MVC 3.1.
With that out of the day, let's have a closer, more detailed look.
Server-Side Support
How do you test a Spring MVC controller today? Most likely through a simple unit test, possibly involving the MockHttpServletRequest and -Response. Pretty trivial to do but it doesn't test enough. Controllers have annotations that express how they are mapped, what request data needs to be extracted, converted, and validated, whether to write to the body of the response, how to handle exceptions, and on and on. All of what the framework does as a result of these annotations, remains untested if you only write simple unit tests.
What if you could re-write these controller unit tests but instead of invoking controllers directly, it would be done through the DispatcherServlet, just as it happens at runtime? And what if you could use a fluent API to specify the request to perform and the response you expect? All of that without the need for a servlet container. That's what Spring MVC Test does. Here is an example:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("servlet-context.xml")
public class SampleTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = webAppContextSetup(this.wac).build();
}
@Test
public void getFoo() throws Exception {
this.mockMvc.perform(get("/foo").accept("application/json"))
.andExpect(status().isOk())
.andExpect(content().mimeType("application/json"))
.andExpect(jsonPath("$.name").value("Lee"));
}
}
MockMvcBuilders.*MockMvcRequestBuilders.*MockMvcResultMatchers.*For code completion assistance, add them as "favorite types" in the Eclipse preferences, or simply remember classes starting with
"MockMvc*".As you can see we're using the new @WebAppConfiguration annotation to load our Spring MVC configuration. Then we inject the resulting WebApplicationContext into a test class field and use it to create a MockMvc, which in turn is used perform requests and define expectations.
Just like with existing controller unit tests, Spring MVC Test builds on the mock request and response from spring-test and does not require a running servlet container. The main difference is that actual Spring MVC configuration is loaded through the TestContext framework and that the request is performed by actually invoking the DispatcherServlet and all the same Spring MVC infrastructure that is used at runtime.
Also similar to existing controller unit tests, you may consider injecting controllers with mock services in order to focus on testing the web layer and avoid hitting a database for example. So instead of loading actual business and persistence services, you can load configuration that creates mocks. For example:
@Configuration
public class MyConfig {
@Bean
public FooService fooService() {
return Mockito.mock(FooService.class);
}
}
or in XML configuration:
<bean class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="org.example.FooService"/>
</bean>
Given that we're not running in an actual servlet container, just how much will and will not work? For the most part everything will work just like it does at runtime. You can even register Servlet filters, enabling things like Spring Security. Most rendering technologies like JSON/XML, Freemarker, Velocity, Thymeleaf, Excel, PDF, etc. All of that will work. The only rendering technology excluded is JSPs since since that requires a servlet container. For JSPs you can still verify the JSP the request was forwarded, what attributes are in the model, whether any exception was raised, and so on.
Client-side REST Tests
What's the idea behind client-side REST tests? If you have code using the RestTemplate, you'll probably want to test it and to that you can target a running server or mock the RestTemplate. The client-side REST test support offers a third alternative, which is to use the actual RestTemplate but configure it with a custom ClientHttpRequestFactory that checks expectations against actual requests and returns stub responses.
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/greeting"))
.andRespond(withSuccess("Hello world", "text/plain"));
// use RestTemplate ...
mockServer.verify();
MockRestRequestMatchers.*MockRestResponseCreators.*For code completion assistance, add them as "favorite types" in the Eclipse preferences, or simply remember classes starting with
"MockRest*".As you can see we create an instance of RestTemplate and pass it to MockRestServiceServer to be configured. Then we define the characteristics of an expected request and provide a stub response to be returned. We could define any number of expected requests and stub responses. At the end of testing we can use the verify method to check if all expected requests were executed.
Next Steps
There is a lot more we could discuss but it's probably best if you give it a try with your own project either using Spring Framework 3.2 RC1 or the standalone project on Github, which works with Spring Framework 3.1.
Recently I went through the exercise myself by adding a comprehensive set of tests for all controller methods of the spring-mvc-showcase. It was a useful exercise since it helped me find one bug. Therefore I expect it to be useful for others as well.
There are also many demo tests in the Spring Framework if you want more examples including tests with async requests, tests with filters, JSON responses, XML responses, and many others.
Similar Posts
- BeanInitializer: wiring dependencies in unit tests
- Putting Spring Web Flow to a Load Test
- Spring MVC 3 Showcase
- Unit Testing with Stubs and Mocks
- Spring MVC 3.2 Preview: Introducing Servlet 3, Async Support




Kent Rancourt says:
Added on November 12th, 2012 at 4:58 pmRossen, this is great! This feels, to me, like a better alternative than firing up an embedded servlet container to do these sort of end-to-end tests. Any thoughts on how to maybe integrate this with Cucumber so that acceptance tests could be written in this fashion?
Rossen Stoyanchev (blog author) says:
Added on November 13th, 2012 at 5:34 amThanks Kent! This doesn't necessarily replace the need for end-to-end tests with a tool like Selenium but it does allow you to test the Web layer quite thoroughly and have full confidence in it before writing higher-level tests. That said Rob Winch has created an HtmlUnit, Selenium/WebDriver, and Geb Spock extension for Spring MVC Test, which allows testing the generated markup.
As for Cucumber, I haven't thought about it but it should be possible. Although the examples above show a continuous chained invocation, you can break that down into stages that prepare a MockMvc, then RequestBuilder, then perform the request, and then assert expectations, which in turn raises AssertionError's as any JUnit test. If you do try it, I would love to see a blog post!
Adrian Smith says:
Added on November 13th, 2012 at 6:31 amthe code:
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = webAppContextSetup(this.wac).build();
}
does not compile for me.
Type mismatch: cannot convert from DefaultMockMvcBuilder<DefaultMockMvcBuilder> to MockMvc
Adrian Smith says:
Added on November 14th, 2012 at 3:27 amApologies, I have this working now! My mistake.
Abraão Isvi says:
Added on November 20th, 2012 at 8:27 amNice!
Dmytro Chyzhykov says:
Added on December 18th, 2012 at 3:11 pmHello, Rossen!
Thank you for the great job!
Are you planning to integrate the spring-test-mvc in subsequent releases or, may be, that module has a different name?
I'm talking about those bunches of useful classes and methods.
Classes:
org.springframework.test.web.server.MockMvc;
org.springframework.test.web.server.ResultActions;
Methods:
org.hamcrest.Matchers.containsString;
org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
org.springframework.test.web.server.result.MockMvcResultMatchers.content;
org.springframework.test.web.server.result.MockMvcResultMatchers.status;
org.springframework.test.web.server.setup.MockMvcBuilders.xmlConfigSetup;
Unfortunately, I couldn't find them in the current 3.2.0.RELEASE
Could you clarify this situation, please?
Thanks in advance.
Rossen Stoyanchev (blog author) says:
Added on December 19th, 2012 at 6:16 amDmytro, you'll need to reference the spring-test module and use the adjusted package name. The only thing that is missing is the xmlConfigSetup method. Configuration is now loaded through the TestContextFramework.
See the migration guide for details as well as the main documentation. I've also updated the post at the top to include this new information. Thanks for bringing it up!
Marlen says:
Added on January 12th, 2013 at 2:45 amThis is a message to the admin. Your website:http://blog.springsource.org/2012/11/12/spring-framework-3-2-rc1-spring-mvc-test-framework/ is missing out on at least 300 visitors per day. I discovered this page via Google but it was difficult to find as you were not on the first page of search results. I have found a website which offers to dramatically increase your traffic to your website: http://aerotraffic.com/web-traffic/. I managed to get over 10,000 visitors per month using their services, you could also get lot more targeted traffic than you have now. Hope this helps
Take care.
Sławek says:
Added on February 25th, 2013 at 2:44 amHello, Rossen
I was attendant at Spring MVC Test framework webinar and after that adopted some simple test to my project.
My question is about test running. When I lunch: mvn clean install or mvn test -Dtest=NAMEControllerTest from terminal (windows 7 cmd)- tests are running, but from my ide (IDEA) I get an error:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.io.FileNotFoundException: src\main\webapp\WEB-INF\servlet-context.xml
I set context xml file path as: @ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-context.xml")
Could you run those tests directly from ECLIPSE?
greetings
Sławek
Rossen Stoyanchev (blog author) says:
Added on February 25th, 2013 at 6:04 amYes, I am able to run from Eclipse. A number of spring-mvc-showcase tests use file-relative context loading. See AbstractContextControllerTests.java. Try running those.
Sławek says:
Added on February 25th, 2013 at 2:10 pmThank you for response.
Dmytro Chyzhykov says:
Added on February 25th, 2013 at 3:49 pmSławek, it works fine for me in IDEA 12 Community Edition.
I tried to run:
- org.springframework.samples.mvc.exceptions.ExceptionControllerTests
- org.springframework.samples.mvc.response.ResponseControllerTests
- org.springframework.samples.mvc.redirect.RedirectControllerTests
Rossen,
What's a pity that Apache Maven doesn't use src/main/webapp as a test resource folder by default for web artifacts. On the one hand it's possible to configure Maven to do that and use "classpath" resource instead of "file" ones, but in this case code becomes dependent on Maven configuration. On the other hand your test configuration code depends on Maven source directory structure. It roughly looks like the "Chicken or the egg" problem.
Could you share you opinion on this problem, please?
Thanks in advance.
Rossen Stoyanchev (blog author) says:
Added on February 25th, 2013 at 6:20 pmDmytro, I don't understand why is it necessary for src/main/webapp to be a test resource folder? If @ContextConfiguration("file:src/main/webapp/..") is that much of an issue, you can also keep your Spring configuration on the classpath.
Dmytro Chyzhykov says:
Added on February 26th, 2013 at 2:40 pmRossen,
Thanks for the right direction!
vlad says:
Added on March 22nd, 2013 at 2:09 pmWe really need a WAR file to download that has basic tests for REST methods, GET, POST, PUT…. with or without views. With the latest Hibernate and Spring libraries.
I like all the framework but i think a basic project to download will help lots of us to start using this testing framework.
Think of it like a Spring MVC barebones project (like the one available in SpringSource) but with mockmvc
Thanks for the great work! i hope my idea gets a good reception
Rossen Stoyanchev (blog author) says:
Added on March 25th, 2013 at 6:30 amThe spring-mvc-showcase should fit that criteria:
https://github.com/SpringSource/spring-mvc-showcase
James Bloom says:
Added on April 2nd, 2013 at 11:36 amHave you tried combining this with jsoup. That way you can access to the HTML, as follows:
Document html = Jsoup.parse(response.getResponse().getContentAsString());
This supports easy element lookup, i.e. CSS selectors, IDs, etc
Rossen Stoyanchev (blog author) says:
Added on April 2nd, 2013 at 12:24 pmJames, we haven't tried jsoup yet but it looks interesting. Assuming request execution in jsoup is pluggable, it should be relatively easy to integrate. If you make any progress feel free to share the results, we'll consider it for inclusion in the framework, etc.
You might also want to know about the https://github.com/SpringSource/spring-test-mvc-htmlunit integration, which has a similar purpose but it sounds like with jsoup we can take a slightly different approach, wrapping its API with ContentResultMatcher's just like we wrap JSONPath for example.
Thanks for your comment!
James Bloom says:
Added on April 3rd, 2013 at 12:26 amIf I'm reading your code correctly I think I'm using a different approach. I am only using MvcMock to send a request to the ServletDispatcher and then passing the response using jsoup (instead a page object).
It feels like the approach I'm using may be simpler but has the draw back of not being able to execute JavaScript embedded in the page.
By the end of the week I'm going to publish a blog article on this
Kevin Smith says:
Added on April 11th, 2013 at 1:55 pmCould you expand on the example of mocking a service in the controller? I am fairly new to Spring and it's not clear to me how the mock service would be injected when the controller is created from the context configuration. I checked spring-mvc-showcase and couldn't find an example, I don't think Mockito is used there at all..?
Rossen Stoyanchev (blog author) says:
Added on April 12th, 2013 at 6:06 amThe spring-mvc-showcase only aims to showcase Spring MVC, so the controllers don't delegate to any services or database. I've shown examples of how to declare Mockito dependencies in Spring config but you can find more complete examples on the web. Here is one.
Kevin Smith says:
Added on April 12th, 2013 at 6:32 amThank you! That's exactly what I was missing.
Paul says:
Added on June 11th, 2013 at 3:30 amHi,
Nice to have a clean way of testing controllers but one question – when using the "standaloneSetup" I use a private class annotated with @Controller. The tests run fine when run as a single test class but when I incorporate them into a bigger test suite (Eclipse or Maven) the @RequestMappings in the private class seem to have taken over.
Other test classes that use the "real" controller fail as the @RequestMapping url is already occupied by the private class. Is there some way to force the private controller to relinquish its mapping?
Rossen Stoyanchev (blog author) says:
Added on June 11th, 2013 at 6:00 amYour test controller is probably getting detected as a Spring bean through a component scan and is then registered based on its request mappings. You'll need to exclude it from the component scan so that it is ignored.
You could also remove the @Controller annotation. The standalone setup doesn't need it since you're registering the controller explicitly.
Paul says:
Added on June 11th, 2013 at 6:59 amyep, I went for the latter. Fixed immediately. Thank you for the speedy repsonse. I think I was blinded by the @Controller annotation in the linked demo tests and the opening line of the javadoc for standaloneSetup "Build a MockMvc by registering one or more @Controller's instances…". Made me think that @Controller was mandatory. Maybe a clarifying line somewhere could help?