Search code examples
javaspring-bootjunitmockitomockmvc

jUnit with Spring MVC always returns 400 on POST


I am developing my first Spring Boot application with backend and frontend. Right now I am writing Unit tests for the Controller in the backend to test the Controller Response Codes. My test class for the Controller looks like this:

@WebMvcTest(controllers = HorseEndpoint.class)
@ActiveProfiles({"test", "datagen"})
public class HorseEndpointTest {

    @MockBean   //the dependencies the controller class needs
    private HorseService horseService;
    @MockBean
    private HorseMapper horseMapper;

    @Autowired
    private MockMvc mockMvc;
    @Autowired
    ObjectMapper objectMapper;

    Horse horseA = new Horse(-50L, "Pferd 1", null, new Date(0), Gender.MALE, null, null, null);

    @Test
    @DisplayName("Adding a valid horse should return the horse")
    public void addingHorse_valid_shouldReturnHorse() throws Exception {

        Mockito.when(horseService.addHorse(horseA)).thenReturn(horseA);

        mockMvc.perform(post("/horses")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(horseMapper.entityToDto(horseA)))
                .characterEncoding("utf-8"))
            .andExpect(status().is(201))
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$.length()").value(1))
            .andDo(print());
    }
}

The code in the Controller class for POST looks like this:

@RestController
@RequestMapping("/horses")
public class HorseEndpoint {

    @PostMapping(value = "")
    @ResponseStatus(HttpStatus.CREATED)
    public HorseDto addHorse(@RequestBody HorseDto horseDto) {
        Horse horse = horseMapper.dtoToEntity(horseDto);
        try {
            horse = horseService.addHorse(horse);
        } catch (ValidationException v) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The horse data provided is invalid: " + v.getMessage(), v);
        }
        return horseMapper.entityToDto(horse);
    }
}

The problem is, as soon as I run the tests, the output file will show this error:

Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 3.046 s <<< FAILURE! - in endpoint.HorseEndpointTest
addingHorse_valid_shouldReturnHorse  Time elapsed: 0.124 s  <<< FAILURE!
java.lang.AssertionError: Response status expected:<201> but was:<400>

Note that calling the POST Method from the frontend works without any problems. Exceptions of type ValidationException are only thrown in the Service Layer, but as I overwrote the function addHorse() with Mockito.when(), so the validation there does never take place, right? So my guess is that it somehow fails to create a valid JSON from the Dto in the test class to pass to the controller. I already had a look on other related SO questions, but none of the solutions seemed to work. Note: I already checked that the Date Types from Test class and Dto class are consistent.

I really appreciate any help!


Solution

  • Your controller don't know about the mocked horseService you create in your test. You have to inject into the controller in some way.

    You can see some examples on how to do that on https://thepracticaldeveloper.com/guide-spring-boot-controller-tests/#mockitoextension-and-mockmvc