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

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)方法,因此出现“调用了但未被验证到”的矛盾。

解决方法

明确指定要验证的子类重载方法即可:

  1. 指定具体参数类型的匹配器:
    // 生产代码中替换成ViewListener.class
    verify(childObj).method5(any(PropertyChangeListener.class));
    
  2. 强制类型转换匹配器:
    // 强制指定匹配子类方法的参数类型
    verify(childObj).method5((PropertyChangeListener) any());
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:17:29