'How to write Unit Test for below Exception Handler method using mockito?

@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, WebRequest request) {
    StringBuilder messageBuilder = new StringBuilder("Validation failed for: ");
    ex.getConstraintViolations()
        .stream()
        .forEach(v -> messageBuilder
            .append("property: [" + v.getPropertyPath() + "], value: [" + v.getInvalidValue() + "], constraint: [" + v.getMessage() + "]"));
    return new ResponseEntity<>(responseBuilder
        .createErrorResponse(INVALID_PARAMETER,
            messageBuilder.toString()), getHeaders(), BAD_REQUEST);
}

I want to test this @ControllerAdvice method



Solution 1:[1]

If you just want to test the method it suffices to create an instance of ConstraintViolationException (your input) and check the output of the handleConstraintViolation method applied to it. You can do somthing like this:

ConstraintViolationException exception = mock(ConstraintViolationException.class);
WebRequest webRequest = mock(WebRequest.class); 
YourControllerAdvice controllerAdvice = new YourControllerAdvice();
Set<ConstraintViolation<?>> violations = new HashSet<>();
ConstraintViolation mockedViolation = mock(ConstraintViolation.class);
given(mockedViolation.getPropertyPath()).willReturn("something");
// mock answer to other properties of mockedViolations 
...
violations.add(mockedViolation);  
given(exception.getContraintViolations()).willReturn(violations);

ResponseEntity<Object> response = controllerAdvice.handleContraintViolation(exception, webRequest);

assertThat(response.getStatusCode(), is(HttpStatus.BAD_REQUEST));

plus maybe other assertions on the response body. However it can be difficult to know how all the different ConstraintViolationException instances thrown by spring might look like.

I would instead suggest that you look at MockMvc, which is part of spring-boot-starter-test. In this way you can test that the exception handler is used as expected and you can verify the ResponseEntity both in the case of constraint violations or not.

@WebMvcTest(YourController.class)
public class YourControllerMvcTest {

  @Autowired
  private MockMvc mvc;

  @Test
  public void constraintViolationReturnsBadRequest() throws Exception {
    // Instantiate the DTO that YourController takes in the POST request
    // with an appropriate contraint violation
    InputDto invalidInputDto = new InputDto("bad data");
    MvcResult result = mvc.perform(post("/yourcontrollerurl")
            .content(invalidInputDto)
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isBadRequest());

    // assert that the error message is as expected
    assertThat(result.getResponse().getContentAsString(), containsString("default message [must match"));
  } 
}

MockMvc has also nice json support so that one can add:

.andExpect(MockMvcResultMatchers.jsonPath("$.field").value("expected value"))

instead of the verifying the response as a string.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 scre_www