javaspringspring-bootspring-webspring-validator

Testing @Validated RestController in standalone MockMvc not working


I have RestController annotated with @Validated for validating path variables / request parmas:

@RestController
@Validated
public class MainController implements ApplicationListener<ApplicationReadyEvent> {

    @Autowired
    private CarsService carsService;

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public void handleException(ConstraintViolationException ex) {}

    @GetMapping(
            value = "/",
            produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> getCars(
            @RequestParam(value = "offset", defaultValue = "0") @PositiveOrZero
                    Integer offset,
            @RequestParam(value = "limit", defaultValue = paginationLimitDefault)
            @Positive @Max(paginationLimitMax)
                    Integer limit) {
        ...
        ...
        Map responseBody = new HashMap<String, Object>();
        responseBody.put("offset", offset);
        responseBody.put("limit", limit);
        return ResponseEntity.status(HttpStatus.OK).body(responseBody);
    }
}

Now, I want to unit test the controller level with standalone mockMvc:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestMainController {

    @InjectMocks
    private MainController mainController;

    @Mock
    private CarsService carsServiceMock;

    private MockMvc mockMvc;

    @Before
    public void initMocks() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
    }

    @Test
    public void getCarsInvalidOffset() throws Exception {
        mockMvc.perform(get("/")
                .param("offset", "-1"))
                .andExpect(status().isBadRequest());
    }

    @Test
    public void getCarsInvalidLimit() throws Exception {
        mockMvc.perform(get("/")
                .param("limit", "0"))
                .andExpect(status().isBadRequest());
        mockMvc.perform(get("/")
                .param("limit", "-1"))
                .andExpect(status().isBadRequest());
        mockMvc.perform(get("/")
                .param("limit", "101"))
                .andExpect(status().isBadRequest());
    }
}   

The problem is that the tests with the invalid params (both tests in the code snippet above) where should have return bad request, actually returning 200 OK and as a result the test fails.
How can I fix it? Thanks.


Solution

  • I suspect that because you are mocking the MainController, the @Validated isn't taking effect. Try this:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest
    @ActiveProfiles("test")
    public class TestMainController {
    
        @Autowired
        private MainController mainController;
    
        @MockBean
        private CarsService carsServiceMock;
    
        @Autowired
        private WebApplicationContext context;
    
        private MockMvc mockMvc;
    
        @Before
        public void initMocks() {
            mockMvc = MockMvcBuilders.webAppContextSetup(context)
            .build();
        }