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

Mockito中doNothing触发UnfinishedStubbingException问题求助

解决Mockito UnfinishedStubbingException问题

这个问题我之前也碰到过,UnfinishedStubbingException的根源是你在stubbing(存根)方法的过程中,不小心触发了另一个真实方法的调用,或者嵌套了未完成的stub操作,打乱了Mockito的内部上下文。咱们一步步来拆解和解决:

先排查明显的笔误

看你的代码里,你stub的是spyAnotherService.getUrl(ID),但在deleteSomething里传入的是spyAnotherService.getRepApiServiceUrl(ID)——这两个方法名不一样!如果这是手滑写错了,那首先得把stub的方法名改成和实际调用的一致,否则你的stub根本不会生效。

核心问题:不要在Stubbing参数中直接调用Spy方法

你当前的代码里,在设置myService.deleteSomething的存根时,直接把spyAnotherService.getRepApiServiceUrl(ID)作为参数传进去了:

Mockito.doNothing().when(myService).deleteSomething(name, spyAnotherService.getRepApiServiceUrl(ID));

这会导致在stubbing myService的过程中,真实调用了spyAnotherService的getRepApiServiceUrl方法(因为Spy默认会执行真实方法,除非你用doReturn提前存根),而这个真实调用可能触发了未预期的逻辑,或者和Mockito的存根流程冲突,从而抛出异常。

正确的两种解决方式

方式1:提前获取Stub后的结果,再传入参数

先存根spy的方法,然后把存根后的结果存到变量里,再用这个变量作为参数设置myService的存根:

// 1. 先存根spy的目标方法(注意方法名要和实际调用的一致)
// 用doReturn可以避免调用真实方法,更安全
Mockito.doReturn(URL).when(spyAnotherService).getRepApiServiceUrl(ID);

// 2. 获取存根后的URL(这里不会调用真实方法)
String mockedApiUrl = spyAnotherService.getRepApiServiceUrl(ID);

// 3. 设置myService的存根,用提前获取的变量作为参数
Mockito.doNothing().when(myService).deleteSomething(name, mockedApiUrl);

方式2:使用参数匹配器

如果你不需要实际获取那个URL,也可以用Mockito的参数匹配器来匹配参数,避免直接调用spy方法:

// 先存根spy的方法
Mockito.doReturn(URL).when(spyAnotherService).getRepApiServiceUrl(ID);

// 使用eq匹配器来指定参数值,这里直接用你要模拟的URL即可
Mockito.doNothing().when(myService).deleteSomething(eq(name), eq(URL));

如果不关心第二个参数的具体值,也可以用anyString()代替eq(URL)。

额外提示:Spy的正确使用姿势

当你使用Spy时,尽量用doReturn(...).when(spy).method(...)来存根,而不是when(spy.method(...)).thenReturn(...)——因为后者会先调用一次真实的方法,如果你真实方法有副作用(比如访问数据库、抛出异常),就会出问题。前者则完全跳过真实方法,直接返回模拟值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:12:40