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();
这样修改后:
setRepository.getSize()会始终返回40;subject.findSetSize()直接返回30,不会执行内部的真实逻辑,日志也不会被打印。
内容的提问来源于stack exchange,提问作者rabong
相关产品推荐
相关产品推荐

