REST Web Services testing with Spring MVC
A previous post introduced the basic features of the Spring MVC test framework. This post covers the testing of a REST web controller: by checking the response status, the content type, and the returned JSON document , we’ll verify if the controller behaves as expected.
The controller to test
The controller to test is rather simple, it just returns a Java object that ends up being serialized in the response. The point here is to test Spring MVC features like argument mapping and serialization.
@Controller public class ContactController { @RequestMapping("/contact/{id}") @ResponseBody public Contact contact(@PathVariable("id") Integer id) { // mimics a call to a business service return new Contact(id,"Test Firstname","Test Lastname"); } }
The test of the controller
Setting up the test
We need to set up the web version (@WebAppConfiguration
) of the Spring TestContext Framework (@RunWith(SpringJUnit4ClassRunner.class)
and @ContextConfiguration
). We embed the configuration in the test, thanks to a @Configuration
inner class. Here is the setup part of the test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @WebAppConfiguration public class ContactControllerTest { @Autowired private WebApplicationContext ctx; private MockMvc mockMvc; @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build(); } (...) @Configuration @EnableWebMvc public static class TestConfiguration { @Bean public ContactController contactController() { return new ContactController(); } } }
Note we use @EnableWebMvc
on the configuration class: this will activate (among others) the REST support. We need this to register the Jackson (JSON) converter in charge of serialization.
The infrastructure is ready, let’s send a (mock) request to our controller.
Sending a request, debugging the response
The whole point of the test is to ensure the controller responds correctly to one of our requests. Our controller is quite simple, so we could send a request and directly check the result with the appropriate expectation API. For more complex cases, like fancy custom JSON serialization, we would typically send the request and use some debugging features to display the response. This would make the writing of the expectations simpler (especially if the returned document is somewhat complex). Let’s do that!
Our first version of the test method sends the request and use andDo(print())
to display the request and response information on the console:
@Test public void contact() throws Exception { Integer id = 1; mockMvc.perform(get("/contact/{id}",id).accept(MediaType.APPLICATION_JSON)) .andDo(print()); }
The execution of the test should output the following on the console:
MockHttpServletRequest: HTTP Method = GET Request URI = /contact/1 Parameters = {} Headers = {Accept=[application/json]} Handler: Type = com.zenika.ContactController Method = public com.zenika.Contact com.zenika.ContactController.contact(java.lang.Integer) Async: Was async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/json;charset=UTF-8]} Content type = application/json;charset=UTF-8 Body = {"id":1,"firstname":"Test Firstname","lastname":"Test Lastname"} Forwarded URL = null Redirected URL = null Cookies = []
In real-world tests, you would typically check the response status, the headers, and the body:
Headers = {Content-Type=[application/json;charset=UTF-8]} Content type = application/json;charset=UTF-8 Body = {"id":1,"firstname":"Test Firstname","lastname":"Test Lastname"}
Let’s see how to do that.
Checking the response
We check the response by calling the andExpect
method on the ResultActions
object returned by the perform
method. The andExpect
needs a ResultMatcher
object and we would typically use ResultMatcher
s provided by the MockMvcResultMatchers
class.
To check the response code, we use the status()
method. We expect 200 (OK):
.andExpect(status().isOk())
To check the content type:
.andExpect(content().contentType("application/json;charset=UTF-8"))
Testing the JSON document can be a pain, especially if you don’t have support for JSON parsing. The good news is Spring MVC test framework supports JsonPath out-of-the-box. Retrieving the value of the id
attribute is like the following:
.andExpect(jsonPath("id").value(id));
Let’s put it all together, here is the full test method:
@Test public void contact() throws Exception { Integer id = 1; mockMvc.perform(get("/contact/{id}",id).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("id").value(id)); }
Pretty simple, isn’t it? Launch the test in your favorite IDE to see the green bar!
And here’s the full version of the test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @WebAppConfiguration public class ContactControllerTest { @Autowired private WebApplicationContext ctx; private MockMvc mockMvc; @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build(); } @Test public void contact() throws Exception { Integer id = 1; mockMvc.perform(get("/contact/{id}",id).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("id").value(id)); } @Configuration @EnableWebMvc public static class TestConfiguration { @Bean public ContactController contactController() { return new ContactController(); } } }
Conclusion
This post covered how to test a Spring MVC REST controller with the Spring MVC out-of-container test framework. We managed to check the controller in terms of input parameters, response status, response headers, and response content. By testing a read-only web service, we only scratched the surface of the framework: one can test the other HTTP operations (POST, PUT, DELETE), requests with some content in the body, more headers, etc. Now, get back to work and test your REST web service layer!
Source code
Hi
Great post and everything clearly explained.
I was wondering how to compare string from response body (not json) with that andExpect()
I know that mockMvc has andReturn() so whole expression can return response – but I wonder that is possible to check simple string against that in body within mockMvc expression?