Mock单元测试异常:预期返回‘Success.’却得到空ResponseEntity求助
根据你描述的情况,明明Mock了gameService.addGame()返回"Success.",但测试中得到空响应,结合代码细节来看,最可能的原因是Mockito的参数匹配未生效,导致gameService.addGame()实际返回了null,最终Spring MVC将ResponseEntity.ok(null)序列化为空响应体。下面具体分析并给出解决办法:
核心原因:GameDTO的对象匹配失败
在你的测试代码中,你创建了一个GameDTO实例并传入when(gameService.addGame(gameDTO)).thenReturn("Success."),但控制器通过@RequestBody接收的是Spring MVC从JSON解析出来的全新GameDTO对象。如果GameDTO类没有重写equals()和hashCode()方法,Mockito会用默认的对象引用相等来匹配参数——这两个对象不是同一个引用,所以Mock的返回值不会生效,gameService.addGame()会返回默认的null,最终导致响应体为空。
另外你提到Postman调用正常,这是因为实际运行时gameService.addGame()会真实执行并返回"Success.",和Mock的逻辑无关,所以接口表现正常。
解决方案
方案1:重写GameDTO的equals()和hashCode()方法
让Mockito可以通过对象的属性值来匹配参数,而不是依赖引用相等。例如:
public class GameDTO { private Long user1Id; private Long user2Id; private String result; // 构造函数、getter、setter @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GameDTO gameDTO = (GameDTO) o; return Objects.equals(user1Id, gameDTO.user1Id) && Objects.equals(user2Id, gameDTO.user2Id) && Objects.equals(result, gameDTO.result); } @Override public int hashCode() { return Objects.hash(user1Id, user2Id, result); } }
方案2:使用Mockito的参数匹配器
如果你不想修改GameDTO类,可以改用any(GameDTO.class)来匹配任意GameDTO对象,这样Mock的返回值就会生效:
// 替换原来的when语句 when(gameService.addGame(any(GameDTO.class))).thenReturn("Success.");
额外验证点
为了确认这个问题,你可以在测试中临时添加一行代码,验证gameService.addGame()的调用情况:
// 在andReturn()之后添加 verify(gameService).addGame(any(GameDTO.class));
如果运行测试时抛出Wanted but not invoked的异常,就说明参数匹配确实失败了,进一步验证了我们的结论。
内容的提问来源于stack exchange,提问作者devo9191

