Tuesday, November 27, 2012

Spring test mvc with Spring 3.2RC1

I had an opportunity earlier to try out Spring-test-mvc and was very impressed with how easy it now makes integration testing of the Spring MVC controllers.

Spring-test-mvc is now packaged with Spring-test module as of Spring 3.2RC1 and has made a few changes which is what I wanted to record for myself here:

First is to include the Spring-test-mvc module, the following is the dependency now that it is packaged with spring-test module:

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-test</artifactId>
 <version>3.2.0.RC1</version>
 <scope>test</scope>
</dependency>

Now on the test side the first change is to include a @WebAppConfiguration annotation:

@WebAppConfiguration
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/mvc-config.xml", "classpath:/META-INF/spring/applicationContext.xml", "classpath:/META-INF/spring/applicationContext-jpa.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class MemberJsonControllerTest {
 
 @Autowired
 private WebApplicationContext wac;




This new annotation instructs Spring test support to load up a WebApplicationContext - a mock ServletContext is automatically assigned to this WebApplicationContext.

Another change from previous version of Spring-test-mvc is the updated package names, the following are the new static imports:

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

Now that a WebApplicationContext is available in the scope of the test, the next step is to get hold of MockMvc which will drive all the controller related tests:

private MockMvc mockMvc;

@Before
public void setup() {
 this.mockMvc = webAppContextSetup(this.wac).build();
}

Once a MockMvc instance is available all the controller tests can be driven using this, consider the following test where I have a series of CRUD actions and tests on the results being performed on a controller:

@Test
public void testAControllerFlow() throws Exception {
 this.mockMvc.perform(post("/membersjson").contentType(MediaType.APPLICATION_JSON).content(String.format(createJson, 1,"One","One", 0).getBytes()))
   .andExpect(status().isOk());
 this.mockMvc.perform(post("/membersjson").contentType(MediaType.APPLICATION_JSON).content(String.format(createJson, 2,"Two","Two", 0).getBytes()))
  .andExpect(status().isOk());
 this.mockMvc.perform(post("/membersjson").contentType(MediaType.APPLICATION_JSON).content(String.format(createJson, 3,"Three","Three", 0).getBytes()))
  .andExpect(status().isOk());  
 
 this.mockMvc.perform(get("/membersjson").contentType(MediaType.APPLICATION_JSON))
   .andExpect(status().isOk())
   .andExpect(content().string(containsString(membersJson)));
 
 this.mockMvc.perform(put("/membersjson").contentType(MediaType.APPLICATION_JSON).content(String.format(createJson, 1,"One","OneUpdated", 0).getBytes()))
  .andExpect(status().isOk());
 
 mockMvc.perform(get("/membersjson").contentType(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$[0].first").value("One"));
 
 mockMvc.perform(get("/membersjson/1").contentType(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(content().string(containsString("OneUpdated")));

}


The tests are very readable thanks to the fluent interfaces and supports matchers on response data based on Hamcrest which I have used above(containsString) and also supports jsonpath for validating json responses.


I have a github project which provides the complete working sample: https://github.com/bijukunjummen/spring-mvc-test-sample.git



1 comment:

  1. Hello,
    Nice one admin. Thanks for sharing this useful info here. such a nice post.

    ReplyDelete