You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot Controller测试Mock返回null问题根因咨询

SpringBoot Controller单元测试Mock返回null根因解析

你的猜测完全正确,问题核心出在Mockito的参数匹配逻辑和Java类默认的equals比对规则上,具体拆解如下:

核心逻辑说明

  • 你在Controller层单元测试中注入的mMakerService是Mockito生成的Mock代理对象,不是真实的Service实例:所有对该对象的方法调用,都需要先匹配你写的打桩规则,匹配成功才会返回你预设的返回值;匹配失败直接返回引用类型的默认值null,完全不会执行真实Service中的业务逻辑,这就是你调试时无法进入Service层断点的直接原因。
  • Mockito默认的参数匹配规则是:调用方法时传入的实际参数,和你打桩时传入的参数,通过equals()方法比对返回true,才算匹配成功。

未加@EqualsAndHashCode时匹配失败的原因

  • 没有在CreateMonsterDto.Request类上加@EqualsAndHashCode注解时,该类没有重写equals()和hashCode()方法,会直接使用Object类的默认实现:只有两个对象指向同一块内存地址(即引用完全相同)时,equals才会返回true,本质比对的是对象内存地址,不是属性内容。
  • 你的测试代码里两处createMonster方法调用传入的参数其实是不同的实例:
    1. 打桩后手动调用的那一次,传入的是你通过getCreateRequest()方法新生成的Request对象
    2. MockMvc发起HTTP请求时,Spring会先把请求体里的JSON反序列化成一个全新的Request对象,再传给Controller层注入的mock service
      这两个Request对象哪怕所有属性值完全一致,也是内存地址不同的两个独立实例,默认equals比对返回false,Mockito识别不到匹配的打桩规则,自然返回null。

添加@EqualsAndHashCode后修复的原因

Lombok的@EqualsAndHashCode(of = "id")注解会为类自动重写equals()和hashCode()方法,只要两个Request实例的id属性值相等,equals比对就返回true。这时候不管是测试代码里builder生成的实例,还是Spring反序列化JSON生成的实例,只要id一致就会被Mockito判定为参数匹配,打桩规则正常生效,就会返回你预设的返回值,不会再出现null。

测试代码存在的额外问题

  • 你当前MockMvc发起请求时,传入的请求体是CreateMonsterDto.Response对象序列化的结果,正常创建接口应该接收Request类型的参数,现在能跑通纯粹是因为两个类字段名一致,反序列化生成的Request对象id刚好匹配打桩规则,属于巧合,建议改成传入Request对象的序列化结果。
  • 测试代码中手动调用mMakerService.createMonster(getCreateRequest())属于多余代码,单元测试只需要校验MockMvc触发的接口调用逻辑即可,不需要手动调用Service方法,这也是你后面需要校验times(2)调用次数的原因,去掉手动调用后改成校验times(1)更符合测试逻辑。

内容的提问来源于stack exchange,提问作者doosic C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:24:22