Introduction To Spring MVC Test Framework

One of the new features introduced with Spring Framework 3.2 release is Spring MVC Test Framework. It is an improvement from the previous versions and added more testing capabilities. For a web application developer, unit testing the web applications are always a challenging point. Getting a real time test environment for web applications require lot of effort. If you are not familiar with Spring framework, please read our introduction articles at Spring Tutorials page.

Spring MVC Test Framework simplifies the testing of Spring MVC applications using the JUnit framework. They claim that this framework offers first class JUnit support. The notable improvement is that you don’t need a servlet container to run the tests. Only missing point is you can not use the JSP pages, but the complete request flow is executed without any server configuration. This tutorial explains how to test your Spring MVC applications using this new feature.

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.

There are two type of implementation is available.

  1. Configuration Loader: First option is to load spring application configuration using the TestContext framework. Which loads the spring configuration and inject the WebApplicationContext to the MockMvc
  2. Standalone: In the second option, we are not loading the entire configuration file. Here we programmatic way of loading the easy Controller components for the testing. However, this way of testing doesn’t offer the 100% integration testing effect. First option is always preferred for the complete integration testing.

Test Using Spring Configuration Loader

This is the most preferred and useful way to do the complete integration testing. In this approach, all the components/controllers are loaded by the configuration loader and tested using the RestTemplate requests. There is no need for the server for executing these test classes. Let us see a simple example how to get start with this approach. Here I am writing the test class for the TestController class which is written in my previous post.


package javabeat.net;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(value=SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:WebContent/WEB-INF/dispatcher-servlet.xml")
public class SpringMVCTestFramework {
    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;
    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }
    @Test
    public void getAccount() throws Exception {
       this.mockMvc.perform(get("/product/1"))
         .andExpect(status().isOk().
.alwaysExpect(content().contentType("application/json;charset=UTF-8")));
    }
}

  1. @RunWith is JUnit annotation which is executing the tests by invoking the class passed as the parameter. It means that the tests are not executed by the in-built API in the JUnit framework. Here we are passing SpringJUnit4ClassRunner class which is the spring framework implementation.
  2. @WebAppConfiguration is a class-level annotation that is used to declare that the ApplicationContext loaded for an integration test should be a WebApplicationContext.
  3. @ContextConfiguration annotation takes the actual configuration file with the file path. Note that, if you just give the file name, it will take the relative path as the root package. To avoid that confusion, we have to specify the file: prefix to give the exact path. You can pass more than one configuration file with the comma separator.
  4. MockMvc is the new addition which does all the magic of injecting the context and use the Fluent API technique for running the integrated tests. In our example, setUp() method configures the MockMvc object for the test execution before any tests are started.
  5. perform() method in the MockMvc object calls the relative path to run the tests. What w have shown in the above example is very simple way of testing if the return value is correct, in the same way you can add multiple checks for return type, return value, data type, etc. and assert the value with the actual value.

To run the above tests, if you are in the Eclipse environment, right click and execute this class Run As –> JUnit Test.

Test Using Standalone

This is the second approach for executing the individual components. It is very useful when developers want to run the individual components for their testing. There is no need for configuring the entire application context. Only the associated Controller components files are configured and executed. This is not efficient way of testing if you want to run multiple components using this approach. Every time it has to add the new controller components and add the configuration to the memory which is very slow in response time.

Lets look at the modified setUp method in the above example.

    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
    }
  1. There is only a slight modification the way MockMvc object is loaded. Instead of configuring the entire application, only the specified controller component is loaded.
  2. However, still you have to specify the @ContextConfiguration annotation for the configuration details.

Which One To Choose?

It depends on the scenario when you are running the tests. Spring docs define it as:

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.

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.

I hope this article gives good idea on how to start using the new Spring MVC Test Framework. You can test the above example by adding the different parameters and exceptions in the perform method.  I would come up with an example only post with much more combination testing methods. Take an instance, you can test whether the returned value is a JSON type, also you can verify if the JSON values are matching with expected results. I want to make this post simple as possible, so have not added a complex example to explain the concepts. If you have any questions or issues while executing the above example, please write it in the comments section.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better