Spring MVC: Introduction in testing

Spring-test-MVC
Testing is one of the most important parts of software development. Well organized testing helps to keep a code of application in a good state, in a working state. There are a lot of different types of test and methodologies. In this article I want to make an introduction in unit testing of applications based on Spring MVC. Don’t hope to read all about Spring MVC testing here, because it’s just a first article about unit testing.

Speak about unit testing without some application, which I’m going to test is deception. I’ll use one of my applications from the previous post, to avoid a gossip. I recommend to make a short overview of the application before you proceed read current post.
The main goal of this tutorial is to demonstrate how to configure unit tests for a Spring MVC application in annotation maner.

Preparations

The first thing which we always have to do before start any development – add of new dependencies in Maven’s pom.xml file. This case isn’t an exception.

...
		
			org.springframework
			spring-test
			${spring.version}
			test
		
		
			org.springframework
			spring-test-mvc
			1.0.0.M1
			test
		
...
	
		
			spring-maven-milestone
			Spring Maven Milestone Repository
			http://maven.springframework.org/milestone
		
	
...

I have added two new dependencies:
#1 spring-test
#2 spring-test-mvc

The first one is for support for testing Spring applications with tools such as JUnit and TestNG. This artifact is generally always defined with a ‘test’ scope for the integration testing framework and unit testing stubs. The second one is for testing Spring MVC server-side and client-side RestTemplate-based code.

Pay your attention that I added a new repository. I did this because spring-test-mvc still isn’t in official maven repository.

Controller for the unit tests

In this post I’m going to write two unit tests for the most simple controller. Here is a code of the controller:

    @Controller  
    public class LinkController {  
          
        @RequestMapping(value="/")  
        public ModelAndView mainPage() {  
            return new ModelAndView("home");  
        }  
          
        @RequestMapping(value="/index")  
        public ModelAndView indexPage() {  
            return new ModelAndView("home");  
        }  
      
    }  

So as you can see the methods in the controller is trivial, they just return some JSP. The testing of the controller implies check of request status (in success case the code should be 200) and verification of the view’s name.

Writing of unit tests for Spring MVC

Here is a quote of Petri Kainulainen:

The heart of the spring-test-mvc is a class called MockMvc that can be used to write tests for any application implemented by using Spring MVC. Our goal is to create a new MockMvc object by using the implementations of the MockMvcBuilder interface. The MockMvcBuilders class has four static methods which we can use to obtain an implementation of the MockMvcBuilder interface. These methods are described in following:

  • ContextMockMvcBuilder annotationConfigSetup(Class… configClasses) method must be used when we are using Java configuration for configuring the application context of our application.
  • ContextMockMvcBuilder xmlConfigSetup(String… configLocations) must be used when the application context of our application is configured by using XML configuration files.
  • StandaloneMockMvcBuilder standaloneSetup(Object… controllers) must be used when we want to configure the tested controller and the required MVC components manually.
  • InitializedContextMockMvcBuilder webApplicationContextSetup(WebApplicationContext context) must be used when we have already created a fully initialized WebApplicationContext object.

I’m going to use the Web Application Context, for this purpose I need to create a class with configurations:

package com.sprhib.init;

import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.*;

@Configuration
@ComponentScan("com.sprhib")
@EnableWebMvc
public class BaseTestConfig {
	
	@Bean
	public UrlBasedViewResolver setupViewResolver() {
		UrlBasedViewResolver resolver = new UrlBasedViewResolver();
		resolver.setPrefix("/WEB-INF/pages/");
		resolver.setSuffix(".jsp");
		resolver.setViewClass(JstlView.class);
		return resolver;
	}

}

And finally the class with the tests:

package com.sprhib.test;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

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;

import com.sprhib.init.BaseTestConfig;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes=BaseTestConfig.class)
public class LinkControllerTest {
	
	@Autowired
	private WebApplicationContext wac;

	private MockMvc mockMvc;
	
	@Before
	public void init() {
		mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
	}
	
	@Test
	public void testHomePage() throws Exception {
		mockMvc.perform(get("/"))
			.andExpect(status().isOk())
			.andExpect(view().name("home"));
	}
	
	@Test
	public void testIndexPage() throws Exception {
		mockMvc.perform(get("/index.html"))
			.andExpect(status().isOk())
			.andExpect(view().name("home"));
	}
	
}

Notice that I have used static imports they provide usage of such methods as get(), status() etc. @WebAppConfiguration is a class-level annotation that is used to declare that the ApplicationContext loaded for an integration test should be a WebApplicationContext.

Look at the project structure after I have added all testing stuff:

Spring-test-MVC

Check the project on GitHub.

I hope everything is clear. Spring test MVC project is a good tool for the testing of the appropriate applications. There’s just one cons lack of documentation and tutorials. In the next tutorials I’m going to develop this theme.

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS
  • http://SpringByExample.com.ua Oleksiy Rezchykov

    Nice article Alexey. I have a few things to add. First of all I do not understand why do you need both spring-test and spring-test-mvc? This is only needed when you have older spring versions and this should be mentioned explicitly. There is a list of things which you CAN and which you cannot do with standalone context – otherwise Rossen would give us only one opportunity. And finally it will be good to have some examples how to mock a service layer in a controllers.

    • Fruzenshtein

      Thanks for the comment

      1. As specified in the documentation, spring-test is required for testing Spring applications with tools such as JUnit and TestNG. Even more, I use static imports in the LinkControllerTest, they are from the spring-test dependency.

      2. Regarding testing of a service layer, I will write some articles about it soon.

  • Philip

    Hi
    I am getting this error
    02/05/2013 3:15:47 PM null null
    SEVERE: javaAccessorNotSet
    any idea why this happening?
    Philip

    • Fruzenshtein

      Unfortunately I have no idea, not enough information.
      Try to rewrite your code from the scratch.

  • http://www.agung-setiawan.com Agung Setiawan

    i get this following error
    java.lang.IllegalStateException: Failed to load ApplicationContext

    try to solve for hours still not yet work properly

    • http://www.agung-setiawan.com Agung Setiawan

      never mind
      after read this book http://www.apress.com/9781430241553 i realized that WebApplicationContext support is begin from Spring 3.2
      Trying for hours i used Spring 3.1.1 lol :D

      • Fruzenshtein

        Cool
        Be more attentive =)