2

I have the following controller:

@RestController
@RequestMapping(value = ROOT_MAPPING)
public class GatewayController {

    @Autowired
    private RequestValidator requestValidator;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(requestValidator);
    }

    @PostMapping(value = REDIRECT_MAPPING)
    public ResponseEntity<ResponseDTO> redirectEndpoint(@Validated @RequestBody RequestDTO requestDTO, BindingResult result) {
        if (result.hasErrors()) {
            // Handle validation errors
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
        }

        // Do other stuff
        return ResponseEntity.status(HttpStatus.OK).build();
    }
}

And this test class:

@RunWith(SpringRunner.class)
@WebMvcTest(GatewayController.class)
public class GatewayControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private RequestValidator requestValidator;

    @MockBean
    private BindingResult bindingResult;

    private JacksonTester<RequestDTO> requestJacksonTester;

    @Before
    public void setUp() throws Exception {
        JacksonTester.initFields(this, new ObjectMapper());
        Mockito.when(requestValidator.supports(ArgumentMatchers.any())).thenReturn(true);
    }

    @Test
    public void whenRedirectWithValidationErrorsThenBadRequestReturned() throws Exception {
        RequestDTO request = new RequestDTO();
        // Set some values

        Mockito.when(bindingResult.hasErrors()).thenReturn(true);

        mockMvc.perform(MockMvcRequestBuilders.post(ROOT_MAPPING + REDIRECT_MAPPING)
            .contentType(MediaType.APPLICATION_JSON)
            .content(requestJacksonTester.write(request).getJson()))
        .andExpect(MockMvcResultMatchers.status().isBadRequest());
    }
}

When I run this code the test case fail with this reason: Status Expected :400 Actual :200

So, what I want to do is to mock the BindingResult which passed as a parameter to the redirectEndpoint method in the Controller so that when calling bindingResult.hasErrors() this should return true and the test case pass.

I did many search but with no luck. Any suggestions how to do that?

Thanks in advance.

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
knemr57
  • 57
  • 2
  • 7

1 Answers1

3

BindingResult is not a bean in the ApplicationContext. Thus, you cannot mock it via @MockBean.

A BindingResult is created for you by Spring MVC for each incoming HTTP request.

Thus, you don't want to mock the BindingResult. In fact, you probably don't want to mock the behavior of your RequestValidator either. Rather, you should ideally use the real implementation of your RequestValidator, pass in invalid request data (via MockMvc), and then verify the response accordingly.

Note that you should be able to include the real implementation of your RequestValidator via @Import(RequestValidator.class) on the test class.

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136
  • Thank you so much @sam-brannen, this solved my problem. Yes, you are correct I should use the real implementation of `RequestValidator`. I removed `requestValidator` and `bindingResult` then added `@Import(RequestValidator.class)` and everything worked fine. – knemr57 Aug 26 '18 at 08:08