Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integration Testing POSTing an entire object to Spring MVC controller

Is there a way to pass an entire form object on mock request when integration testing a spring mvc web app? All I can find is to pass each field separately as a param like this:

mockMvc.perform(post("/somehwere/new").param("items[0].value","value")); 

Which is fine for small forms. But what if my posted object gets larger? Also it makes the test code look nicer if I can just post an entire object.

Specifically I'd like to test the selection of multiple items by checkbox and then posting them. Of course I could just test posting a single item, but I was wondering..

We're using spring 3.2.2 with the spring-test-mvc included.

My Model for the form looks something like this:

NewObject {     List<Item> selection; } 

I've tried calls like this:

mockMvc.perform(post("/somehwere/new").requestAttr("newObject", newObject)  

to a Controller like this:

@Controller @RequestMapping(value = "/somewhere/new") public class SomewhereController {      @RequestMapping(method = RequestMethod.POST)     public String post(             @ModelAttribute("newObject") NewObject newObject) {         // ...     } 

But the object will be empty (yes I've filled it before in the test)

The only working solution I found was using @SessionAttribute like this: Integration Testing of Spring MVC Applications: Forms

But I dislike the idea of having to remember to call complete at the end of every controller where I need this. After all the form data does not have to be inside the session, I only need it for the one request.

So the only thing I can think of right now is to write some Util class that uses the MockHttpServletRequestBuilder to append all the object fields as .param using reflections or individually for each test case..

I don't know, feeld un-intuitive..

Any thoughts / ideas on how I might make my like easier? (Apart from just calling the controller directly)

Thanks!

like image 914
Pete Avatar asked Jun 17 '13 08:06

Pete


People also ask

Is MockMvc a unit or integration test?

Technically speaking, tests using MockMvc are in the boundaries between unit and integration tests. They aren't unit tests because endpoints are tested in integration with a Mocked MVC container with mocked inputs and dependencies.

Does Spring support integration testing?

The Spring Framework provides first-class support for integration testing in the spring-test module. The name of the actual JAR file might include the release version and might also be in the long org. springframework.

What does MockMvc perform do?

The MockMvc instance is used to perform GET request that expects a JSON response. We check the response for a 200 'OK' response code, a JSON content type and a JSON response body containing the requested account.


1 Answers

I had the same question and it turned out the solution was fairly simple, by using JSON marshaller.
Having your controller just change the signature by changing @ModelAttribute("newObject") to @RequestBody. Like this:

@Controller @RequestMapping(value = "/somewhere/new") public class SomewhereController {      @RequestMapping(method = RequestMethod.POST)     public String post(@RequestBody NewObject newObject) {         // ...     } } 

Then in your tests you can simply say:

NewObject newObjectInstance = new NewObject(); // setting fields for the NewObject    mockMvc.perform(MockMvcRequestBuilders.post(uri)   .content(asJsonString(newObjectInstance))   .contentType(MediaType.APPLICATION_JSON)   .accept(MediaType.APPLICATION_JSON)); 

Where the asJsonString method is just:

public static String asJsonString(final Object obj) {     try {         final ObjectMapper mapper = new ObjectMapper();         final String jsonContent = mapper.writeValueAsString(obj);         return jsonContent;     } catch (Exception e) {         throw new RuntimeException(e);     } }   
like image 163
nyxz Avatar answered Sep 20 '22 02:09

nyxz