Psycho Punch Psycho Punch - 10 days ago 6
Groovy Question

How do I test form submission with Spring MVC test?

Most of my experience with creating controllers with Spring are for REST controllers that consume JSON formatted requests. I've been searching for documentation on how to do testing for form submission, and so far this is how I understand it should go using

MockMvc
:

MvcResult result = mockMvc.perform(post("/submit")
.param('title', 'test title')
.param('description', 'test description'))
.andReturn()


However, I'm not sure how to map the form parameters to a model object. I've seen the
@ModelAttribute
annotation pop up in my searches but I can't figure out how it should be used for mapping. In addition, this quick start guide from the official documentation does not elaborate on how things like
th:object
and
th:field
translate to HTML and subsequently to URL encoded form.

I have my controller code similar to the following:

@PostMapping('/submit')
def submit(@ModelAttribute WriteUp writeUp) {
//do something with writeUp object
'result'
}

Answer

I discovered through trial and error that my specific problem might have been Groovy specific. There test code and the controller code, it turns out, have no issues. To reiterate, for testing form submission, use the param method through perform method of MockMvcRequestBuilders. Another thing to note is that this doesn't seem to work if content type is not specified. Here's a sample test code that works for me:

MvcResult result = webApp.perform(post("/submit")
        .contentType(APPLICATION_FORM_URLENCODED) //from MediaType
        .param('title', 'test title')
        .param('description', 'test description'))
        .andReturn()

As you can see, it's not much different from what I posted originally. The controller code is pretty much just the same, with @ModelAttribute working just fine.

The problem with my setup though was that since I was using Groovy, I assumed that getters and setters were automatically generated in my WriteUp class. Here's how the WriteUp class looked originally:

class WriteUp {
    private String title
    private String description
}

I haven't written code in Groovy for a while, and the last time I did, classes like the one above can be assumed to have getters and setters implicitly. However, it turns out that is not the case. To solve my specific issue, I updated the access modifier in the fields to be default (package level):

class WriteUp {
    String title
    String description
}