Mockito验证异常:调用了method5却提示未按预期调用
Mockito验证矛盾:明明调用了method5却提示未触发
我在用Mockito做单元测试时碰到一个诡异的问题:Mockito提示childObj.method5(<any>)从未被调用,但同时又在交互记录里列出了method5的实际调用记录。
错误输出
Wanted but not invoked: childObj.method5(<any>); -> at de.tejoe.ViewTest.init(ViewTest.java:36) However, there were exactly 5 interactions with this mock: childObj.method1("foo"); -> at de.tejoe.View.init(View.java:257) childObj.method2([null]); -> at de.tejoe.View.init(View.java:258) childObj.method3(); -> at de.tejoe.View.initAlarms(View.java:259) childObj.method4(true); -> at de.tejoe.View.init(View.java:261) childObj.method5(de.tejoe.View$ViewListener@1c82b8ef); -> at de.tejoe.View.init(View.java:262)
使用的Mockito版本
testImplementation 'org.mockito:mockito-core:3.12.4'
核心原因:方法重载
排查后发现问题出在方法重载上:method5存在两个不同的签名——父类/接口中定义的是method5(Object x),子类中又重载了一个method5(ViewListener x)(原型代码中用PropertyChangeListener模拟)。
原型复现代码
class MockitoErrorTest { interface A { void method5(Object x); } private class AImpl implements A { public void method5(Object x) {} } private class B extends AImpl { void method1(String x) {} void method2(Object[] x) {} void method3() {} void method4(boolean flag) {} void method5(PropertyChangeListener x) {} } private class C { B child; B getChild() { return child; } void init() { B x = getChild(); x.method1("foo"); x.method2(new Object[] {null}); x.method3(); x.method4(true); x.method5(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt){} }); } } @Test void init() { C vo = mock(C.class); B childObj = mock(B.class); when(vo.getChild()).thenReturn(childObj); doCallRealMethod().when(vo).init(); vo.init(); verify(childObj).method3(); verify(childObj).method4(true); // 原型代码中这个验证能通过 // 但生产代码中验证失败 // 暂时没发现两者差异 verify(childObj).method5(any()); } }
问题解析与解决方法
为什么会出现矛盾?
Mockito处理重载方法时,会根据验证时传入的参数匹配器推断目标方法签名。当你用verify(childObj).method5(any())时,any()默认匹配Object类型,Mockito会把验证请求绑定到父类的method5(Object)方法上,但实际调用的是子类重载的method5(ViewListener)方法,因此出现“调用了但未被验证到”的矛盾。
解决方法
明确指定要验证的子类重载方法即可:
- 指定具体参数类型的匹配器:
// 生产代码中替换成ViewListener.class verify(childObj).method5(any(PropertyChangeListener.class)); - 强制类型转换匹配器:
// 强制指定匹配子类方法的参数类型 verify(childObj).method5((PropertyChangeListener) any());
内容的提问来源于stack exchange,提问作者tejoe
相关产品推荐
相关产品推荐

