【问题标题】:Spring boot unit test by Junit 5 why mock return nullJunit 5的Spring Boot单元测试为什么模拟返回null
【发布时间】:2021-01-24 19:21:52
【问题描述】:

这是我的控制器:-

@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
public class ScoreService {

    @Autowired
    private ScoreRepository scoreRepository;

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

如果我通过邮递员 POST 请求,它会起作用

http://localhost:8080/score/add

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

它将数据保存在数据库中并响应相同的分数。

但我正在尝试按以下方式进行单元测试,但无法按预期工作。

@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"));
    }
}

在上面的测试中,当我执行发布请求 scoreService.save(score) 时返回 null 而不是控制器代码中的模拟分数。为什么?怎么了?

【问题讨论】:

  • 可能有误,但您是否需要 @BeforeEach(){} 中的 MockitoAnnotations.open(this); 才能启用注释?

标签: java spring-boot unit-testing junit mockito


【解决方案1】:

模拟返回null 意味着传递给save() 的值不等于预期值。这是我会尝试的:

  1. Score 是否正确实施equals()
  2. 试试when(scoreService.save(any())).thenReturn(expectedScore)。无论参数如何,这都应始终返回 expectedScore
  3. 尝试调试它并检查通过的分数实际上是什么样的。

【讨论】:

  • 感谢您的回答。为什么我需要在 Score 中使用 equals()?
  • 如果 Score 没有实现 equals,则在确定相等性时仅比较引用。 expectedScore 和反序列化 JSON 有效负载时生成的任何内容在值方面可能相等,但它们的引用不同。有关详细信息,请参阅stackoverflow.com/questions/7520432
猜你喜欢
  • 1970-01-01
  • 2019-10-03
  • 2020-12-16
  • 1970-01-01
  • 1970-01-01
  • 2020-05-02
  • 2018-09-12
  • 1970-01-01
  • 2018-07-19
相关资源
最近更新 更多