javaspringspring-bootmockitoinvocationtargetexception

JUnit RestControllerTest for @PutMapping throws InvocationTargetException


I'm building a microservice using Spring Boot. I wrote an API with GET-, POST-, PUT-, DELETE- Methods, run the application and tested it using Postman - everything's working fine...

But testing the PUT-Method fails with

java.lang.AssertionError: Status expected:<204> but was:<400>

Running the test in debug-mode and stepping throw throws an InvocationTargetException:

InvocatioTargetException

My RestController-Methods looks like this:

@PutMapping(value = "/{id}")
public ResponseEntity updateSongById(@PathVariable("id") Integer id, @RequestBody @Validated 
SongDto songDto) {
    // TODO Add authorization
    SongDto song = songService.getSongById(id);
    if (song == null)
        return new ResponseEntity(HttpStatus.BAD_REQUEST);
    return new ResponseEntity(songService.updateSong(id, songDto), HttpStatus.NO_CONTENT);
}

songService.getSongById(id):

@Override
public SongDto getSongById(Integer id) {
    return songMapper.songToSongDto(songRepository.findById(id)
        .orElseThrow(NotFoundException::new));
}

The SongRepository is just a simple Interface which extends JpaRepository<Song, Integer>.

My failing test looks like this:

@Test
void updateSongById_success() throws Exception {
    when(songService.updateSong(anyInt(), any(SongDto.class))).thenReturn(getValidSongDto());
    String songDtoJson = objectMapper.writeValueAsString(getValidSongDto());
    mockMvc.perform(put("/rest/v1/songs/1")
            .content(songDtoJson)
            .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isNoContent());
}

And getValidSongDto() just provides a Dto used in my tests:

private SongDto getValidSongDto() {
    return SongDto.builder()
            .id(1)
            .title("TestSongValid")
            .label("TestLabelValid")
            .genre("TestGenreValid")
            .artist("TestArtistValid")
            .released(1000)
            .build();
}

I really don't understand at the moment, what I did wrong to make this test fail and also couldn't find anything in the internet which helped me solving this problem, so far. So, therefor I'd be very thankful, if anybody could tell me what's wrong here and how to solve this issue.

Thank you very much!!


Solution

  • You need to return the value for songService.getSongById as shown below

    @Test
    void updateSongById_success() throws Exception {
        
        when(songService.getSongById(Mockito.any())).thenReturn(getValidSongDto());
        
        when(songService.updateSong(anyInt(), any(SongDto.class))).thenReturn(getValidSongDto());
        
        String songDtoJson = objectMapper.writeValueAsString(getValidSongDto());
        
        mockMvc.perform(put("/rest/v1/songs/1")
                .content(songDtoJson)
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isNoContent());
    }