Integration testing Spring controllers

Time-constrained projects sometimes mandate crude realism as to the type and extent of test coverage in a software project. You’ll find arguments for and against testing in the entire spectrum of opinions from “tests are luxury we can’t afford” to “regressions are luxury we can’t afford”.
Constrained or not, there is rarely a good excuse for a bad application architecture. The cool science happens in the labs of big companies, most projects are best served with tried and trialled recipes – so even when working in a rush, an application ought to at least clearly separate concerns into modular components. Apart from code reuse ( = lower costs), separation of concerns increases testability and helps confine errors to code localities rather than spread them across several parts of the application.
I’ll advocate integration tests against the service layer as the golden middle: a distinct step of a use case is tested, including execution paths across security, auditing, business logic, persistence and every other functional or technical aspect that has been layered over the business logic. Spring facilitates these type of tests with modular application contexts which load the beans and dependencies needed for test.
There are various approaches to integration testing in Spring; a really good series of articles is here [1]. The common approach is to locate a controller, directly invoke its methods from the test and inspect the returned ModelAndView. That approach is fast and easy though it leaves the HTTP layer untested (security, URL mapping, filters, rendering). The same series of articles discusses testing a REST service with Spring’s MockMvc utilities which at least will test parts of the HTTP handling. An important detail the article leaves out: crucial parts of how the Spring configuration handles HTTP remain untested. Which parts exactly depends on the features used. In the repository [2] I played around with various layers on top of a service (validation, transactions, security, exception handling and interceptors) and found that MockMvc requests would bypass one or more layers. My untested theory is that it picks the wrong RequestMappingHandlerAdapter from the web application context.
A perfect approach would be to start the entire web application in a servlet container (i.e. Grizzly), but that might become cumbersome, slow and introduce class loading issues. Once more, looking for the golden middle, instantiating the DispatcherServlet together with the application context proves to be a practical approach.

A DispatcherServlet is easily instantiated:

@Before
public void setup(){
   MockServletConfig config = new MockServletConfig("spring");
   config.addInitParameter(
      "contextConfigLocation",
      "classpath:webshop/environment-context.xml, classpath:webshop/application-context.xml");
   dispatcherServlet = new DispatcherServlet();
   dispatcherServlet.init(config);
}
Talking to it isn’t any harder:
MockHttpServletRequest request = new MockHttpServletRequest(dispatcherServlet.getServletContext(), "GET", url);
MockHttpServletResponse response = new MockHttpServletResponse();
dispatcherServlet.service(request, response);
System.out.println(response.getContentAsString());

 

Resources

[1] Spring MVC Test Tutorial
[2] Scala sandbox

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.