6

Controller

@RestController
@Validated
class MyController {

    @GetMapping("/foo")
    public String unwrapped(@Min(1) @RequestParam("param") int param) {
        return Integer.toString(param);
    }

    @GetMapping("/bar")
    public String wrapped(@ModelAttribute @Valid Wrapper bean) {
        return Integer.toString(bean.param);
    }

    static class Wrapper {

        @Min(1)
        int param;

        public void setParam(final int param) {
            this.param = param;
        }
    }
}

Test

public class MyControllerTest {

    MyController controller = new MyController();
    MockMvc mockMvc = MockMvcBuilders
            .standaloneSetup(this.controller)
            .build();

    @Test // fails
    public void unwrapped() throws Exception {
        this.mockMvc.perform(get("/foo")
                .param("param", "0"))
                .andExpect(status().isBadRequest());
    }

    @Test // passes
    public void wrapped() throws Exception {
        this.mockMvc.perform(get("/bar")
                .param("param", "0"))
                .andExpect(status().isBadRequest());
    }
}

To enable (unwrapped) method parameter validation in spring the controller has to be annotated with @Validated and the MethodValidationPostProcessor must be added to the context.
Is it possible to add the MethodValidationPostProcessor bean to the standalone setup ?
The question might be reduced to how to add a BeanPostProcessor to a standalone MockMvc setup ?

Bax
  • 4,260
  • 5
  • 43
  • 65
  • it is working for \@validated controller with method consisting dto arguments with validation annotations upon its attributes. but not for validation annotations against controller method arguments directly. for latter case you need integation test (\@RunWith(SpringRunner.class and \@SpringMvcTest). and don't forget that \@validated upon class produces 500 http error on ConstraintValidationException and for required Bad Request response you have to implement exception handler per exception class. – Simon Logic Feb 10 '21 at 20:37

1 Answers1

7

Is it possible to add the MethodValidationPostProcessor bean to the standalone setup ?

No, that is unfortunately not possible when using MockMvcBuilders.standaloneSetup() since that creates a StubWebApplicationContext behind the scenes which does not support BeanPostProcessors.

Once SPR-6380 has been addressed (currently in the Spring Framework 5.x backlog), you will no longer need to rely on the MethodValidationPostProcessor. However, in the interim you will need to switch to the use of MockMvcBuilders.webAppContextSetup() in order to be able to test the behavior added to you controller via MethodValidationPostProcessor.

Original Erroneous Suggestion

I don't think it's possible to do that directly; however, you could create a custom subclass of StandaloneMockMvcBuilder that overrides the initWebAppContext() method, delegates to super.initWebAppContext() to create the WebApplicationContext, and then registers the MethodValidationPostProcessor bean programmatically via org.springframework.test.web.servlet.setup.StubWebApplicationContext.addBean(String, Object).

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • OK. Out of curiosity, have you verified that your `unwrapped()` method is properly validated when you deploy your app? – Sam Brannen Mar 08 '18 at 17:33
  • I ask because validation is not officially supported for a `@RequestParam`. See the following JIRA issue for details: https://jira.spring.io/browse/SPR-6380 – Sam Brannen Mar 08 '18 at 17:34
  • Never mind: I just noticed this comment in that issue: https://jira.spring.io/browse/SPR-6380?focusedCommentId=135728&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-135728 – Sam Brannen Mar 08 '18 at 17:36
  • it does, a `ConstraintViolationException` is thrown – Bax Mar 08 '18 at 18:31
  • I apologize: my original suggestion could never work since `StubWebApplicationContext` explicitly does not support `BeanPostProcessor`s. However, I'll edit my answer to include an authoritative response. – Sam Brannen Mar 09 '18 at 11:47