1

I am trying to write Spring MVC Tests to test Spring controllers. Currently if I wanted to test a controller method with this signature:

@RequestMapping(value = "/new/save", method = RequestMethod.POST)
@Transactional
public String postGateway(@Valid GatewayForm gatewayForm, BindingResult bindingResult, RedirectAttributes flash, Model model)

I would use MockMVC in this manner to populate the GatewayForm object parameter:

mvc.perform(
                post("/new/save")
                        .sessionAttr("account", account)
                        .param("serialNumber", "SN1QRTY334V")
                        .param("branchId", "1")
                        .param("model", "1")
                        .param("templateId", "1")

The problem with this is that I can only set String/primitive values onto the GatewayForm object using the .param(String, String) method.

So there are object instance variables on the GatewayForm above that I cannot set. I have seen other people instead post a JSON string of the object, but this would require changing the implementation of the controller methods to consume "application/json" which I do not want to do.

Can anybody advise?

  • 2
    You shouldn't pass an object to your controller in integration tests http://stackoverflow.com/a/17143677/1935341 – Mateusz Dryzek Jan 07 '16 at 07:38
  • Second that. It's bad practice. – horatius Jan 07 '16 at 07:41
  • Okay it seems I must try out this postForm() method instead of post(). Let me try just that – Duran Wesley Harris Jan 07 '16 at 07:44
  • 2
    The point of MockMVC is to simulate a request and not to directly test the method `postGateway`. A request will only contain text. A client doesn't send a `GatewayForm` object, it sends parameters. – a better oliver Jan 07 '16 at 08:35
  • That make 100% sense, but yet there is not really a facility to do so without mapping to JSON. Or am I missing something? Think I must inspect the parameters of the real-life form post before I continue arguing for nothing.. – Duran Wesley Harris Jan 07 '16 at 08:59
  • Okay I see now... the non-primitive values on the form object were populated on the server side before the post even occurs. Now it all makes sense.Plus the test code is much neater this way – Duran Wesley Harris Jan 07 '16 at 09:20

1 Answers1

0

As the comments to the question state that strings are essentially the input for HTTP requests parameters, the goal is to convert your form object into an accepted string.

Looking at the spring-mvc-test-utils library there are multiple strategies to converting an object into a String. However, the default strategy for converting an object into a String within the source code is to use:

String.valueOf(Object object)

For example my use case was to pass a List as parameters into my integration test. My controller accepts an object with attributes:

public class MyObjectThatTheControllerExpects {     
    List<SomeEnum> listOfEnums;
    Long id
    ...

Therefore, my integration test posts the parameters like so:

mvc
    .perform(
        post("/some/endpoint")
            .param("listOfEnums", String.valueOf(SomeEnum.SOMEENUMCONSTANT), String.valueOf(SomeEnum.SOMEOTHERENUMCONSTANT))
            .param("id", "100")

I am sure this may not be appropriate for more complex classes. However, for this trivial case it works.

Hope it helps!