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

JUnit5中Stubbing时Mock值被覆盖的原因解析

为什么Mock的SetRepository.getSize()返回值看似被Stub的ListService.findSetSize()覆盖?

问题还原

你在测试中Mock了SetRepository,让其getSize()返回40;随后又Stub了ListService(Spy实例)的findSetSize()方法让其返回30。但实际调用时发现setRepository.getSize()返回30,而非预期的40,同时findSetSize()内部的日志显示第一次输出40、第二次输出30。

核心原因分析

问题出在你对Spy对象使用when(spy.method()).thenReturn(value)的Stub方式上:

  • Mockito对Spy对象的when()语法会触发真实方法执行:当你执行when(subject.findSetSize()).thenReturn(30)时,Mockito会先完整执行一次findSetSize()的真实逻辑,再将该方法的后续调用Stub为返回30。
  • 第一次真实执行的影响:在这次真实执行中,findSetSize()会调用setRepository.getSize(),此时setRepository的Stub已经生效,返回40,所以你看到第一次日志输出40。
  • 关于setRepository.getSize()返回30的误解:
    独立Mock的setRepository的Stub并没有被覆盖,它依然会返回40。你看到的返回30,大概率是混淆了setRepository.getSize()和subject.findSetSize()的返回值——比如测试代码中的System.out.println(setRepository.getSize())可能误写为subject.findSetSize(),否则从逻辑上,Spy的Stub不会影响独立Mock的行为。
  • 第二次日志输出30的原因:如果你的日志确实输出了30,说明subject.findSetSize()的Stub没有生效,真实逻辑仍在执行。这时候setRepository.getSize()的返回值被修改的可能性极低,更可能是你误操作了Stub逻辑。

正确的Spy Stub方式

如果想避免触发真实方法,同时Stub Spy对象的方法,应该使用doReturn语法:

// 替换原有的when(subject.findSetSize()).thenReturn(30)
doReturn(30).when(subject).findSetSize();

这样修改后:

  1. setRepository.getSize()会始终返回40;
  2. subject.findSetSize()直接返回30,不会执行内部的真实逻辑,日志也不会被打印。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:55:36