0

Here is my controller:-

@RestController
@RequestMapping(ScoreBoardController.REQUEST_URL)
public class ScoreBoardController {
    public static final String REQUEST_URL = "/score";       
    public static final String POST_REQUEST = "/add";
    public static final String GET_ALL_REQUEST = "/all";
    public static final String DELETE_BY_ID = "/deleteById/{id}";
    public static final String DELETE_BY_NAME = "/deleteByName/{name}";
    public static final String DELETE_BY_ROUND_PATH_VAR = "/deleteByRoundPath/{round}";
    public static final String DELETE_BY_ROUND_PARAM = "/deleteByRoundParam";
    public static final String UPDAATE_NAME_BY_ID_PATH_VAR = "/updateNameByIdPath/{id}/{name}";
    public static final String UPDATE_NAME_BY_ID_PARAM = "/updateNameByIdParam";
    public static final String UPDATE_RESULT_BY_ID_PATH_VAR = "/updateResultByIdPath/{id}/{result}";
    public static final String UPDATE_RESULT_BY_ID_PARAM = "/updateResultByIdParam";
    public static final String GET_BY_ID = "/getById/{id}";

    private ScoreService scoreService;

    public ScoreBoardController(ScoreService scoreBoardService) {
        this.scoreService = scoreBoardService;
    }


    @ApiOperation(value = "Add a new score post socre as json body")
    @PostMapping(path = POST_REQUEST, produces = MediaType.APPLICATION_JSON_VALUE)
    public Score save(
            @ApiParam(value = "A score to save into db")
            @RequestBody Score score) {
        return scoreService.save(score);
    }

}

Service:-

@Service
public class ScoreService {

    @Autowired
    private ScoreRepository scoreRepository;

    public Score save(Score score) {
       return scoreRepository.save(score);
    }
}

It works if I POST request by the postman

http://localhost:8080/score/add

{
    "name": "test4",
    "round": 4,
    "result": "WIN"
}

It saves the data in DB and response same score.

But I am trying to unit test as follows that doesn't work as expected.

@WebMvcTest({ScoreBoardController.class})
class ScoreBoardControllerTest {

    @MockBean
    private ScoreService scoreService;

    @Autowired
    private MockMvc mockMvc;
  
    @Test
    void save() throws Exception {
        Score expectedScore = new Score(1l, "name", 1, Result.WIN, null);
        String jsonScore = "{ \"id\": 1, \"name\": \"name\", \"round\" : 1, \"result\" : \"WIN\", \"timestamp\": null  }";
        when(scoreService.save(expectedScore)).thenReturn(expectedScore);
        var ret = scoreService.save(expectedScore); //  mock return correctly

        mockMvc.perform( post(ScoreBoardController.REQUEST_URL+ScoreBoardController.POST_REQUEST)
                .content(jsonScore)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").exists())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1l))
                .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("name"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.result").value("WIN"));
    }
}

On the above test when I perform post request scoreService.save(score) return null instead of mocked score in the controller code. Why? What is wrong?

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
masiboo
  • 4,537
  • 9
  • 75
  • 136
  • May be wrong but do you need `MockitoAnnotations.open(this);` in an @BeforeEach(){} to enable the annotations? – Jcov Jan 25 '21 at 00:29

1 Answers1

1

The mock returning null means that the values passed to save() is not equal to the expected value. This is what I would try:

  1. Is Score implementing equals() correctly?
  2. Try with when(scoreService.save(any())).thenReturn(expectedScore). This should always return expectedScore regardless of the parameter.
  3. Try to debug it and check what the passed Score actually looks like.
EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
  • Thanks for the answer. Why do I need equals() in Score? – masiboo Jan 25 '21 at 11:23
  • If Score does not implement equals only the references are compared when determining equality. expectedScore and whatever is generated when deserializing the JSON payload might be equal value-wise but not their references. See https://stackoverflow.com/questions/7520432 for more details. – EricSchaefer Jan 25 '21 at 11:26