1

I am trying to test my controller endpoint and my requestbody annotated with @Valid annotation. My Testclass looks like the follow:

@RunWith(SpringRunner.class)
@WebMvcTest(value = BalanceInquiryController.class, secure = false)
public class BalanceInquiryControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private BalanceInquiryController balanceInquiryController;

    @Test
    public void testGetBalanceInquiry() throws Exception {
        RequestBuilder requestBuilder = MockMvcRequestBuilders
                .post("/com/balanceInquiry")
                .accept(MediaType.APPLICATION_JSON)
                .content("{\"comGiftCard\":{\"cardNumber\":\"1234567890\",\"pinNumber\":\"0123\"},\"comMerchant\":\"MERCHANT1\"}")
                .contentType(MediaType.APPLICATION_JSON);

        MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
        MockHttpServletResponse response = mvcResult.getResponse();
        assertEquals(HttpStatus.OK.value(), response.getStatus());
    }
}

My Controller - @PostMapping looks like that:

@PostMapping(value = "/com/balanceInquiry")
public ResponseEntity<?> getBalanceInquiry(@Valid @RequestBody BalanceInquiryModel balanceInquiry, Errors errors) {
    if (errors.hasErrors()) {
        return new ResponseEntity<String>("Validation error", HttpStatus.BAD_REQUEST);
    }
    //do any stuff...
    return new ResponseEntity<BalanceInquiryResponse>(balanceInquiryResponse, HttpStatus.OK);
}

My BalanceInquiryModel is annotated with @Valid and has some hibernate and custom validations behind. Those validations are all ok and already unit tested.

What I like to test is my endpoint where I send a valid json request body expecting a 200 response and also an invalid json request body expecting a 400 response validated by the set @Valid implementation.

For example an unvalid call is to send no pinNumber or length < 4.

I have read some threads and some uses MockMvcBuilders.standaloneSetup() to mock the full controller. But I wont do a full integration test.

Not quite sure how to go on with this situation and if I should go on.

P.S.: At the moment I get always a 200 response no matter if the validation should give an error or not.

Here a gist for more code and the validation classes/models.

Patrick
  • 12,336
  • 15
  • 73
  • 115

1 Answers1

3

Here's one of my example I work on my project hope it help you out:

I have a global exception handler to handler my MethodArgumentNotValidException and throw it

@RequestMapping(value = "/add", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {

        User savedUser = userService.save(user);

        return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
    }


public void testAdduser() throws Exception{
        final User request = new User();
        request.setFirstName("Test");
        request.setLastName("some description");

        mockMvc.perform(post(END_POINT+"/add")
                .contentType(MediaType.APPLICATION_JSON)
                .content(stringify(request))

        ).andDo(print()).andExpect(status().isUnprocessableEntity())
        ;
    }
private String stringify(Object object) throws JsonProcessingException {
        return new ObjectMapper().writeValueAsString(object);
    }

Update:

I think your main problem is that you are using @WebMvcTest in stead of @SpringBootTest.

the different between 2 of them is that:

@SpringBootTest annotation will loads complete application and injects all the beans which is can be slow.

@WebMvcTest - for testing the controller layer. it doesn't inject other bean beside the @RestController

so if you are just testing just pure controller to see u can reach the endpont then you can just use @WebMvcTest which will make your test run faster.

but in your case, you want it to run the spring validation, you will need to use @SpringBootTest

for detailed: https://spring.io/guides/gs/testing-web/

Chi Dov
  • 1,447
  • 1
  • 11
  • 22