You need to enable JavaScript to run this app. 为何模拟单例依赖时Mockito仍调用saveContract真实方法?
优惠活动
大模型
产品
解决方案
定价
更多

为何模拟单例依赖时Mockito仍调用saveContract真实方法?

场景下Mockito调用真实方法的核心原因

结合你贴出的全部代码,按出现概率从高到低排查,基本逃不开下面几个问题:

1. 类名拼写不匹配,压根没mock到实际依赖

你业务代码里调用的单例类是 ContractDao(驼峰写法,后缀为Dao,仅首字母D大写),但测试类里@Mock标注的对象类型是 ContractDAO(DAO三个字母全大写)。Java语言严格区分大小写,这两个是完全独立的类,你相当于给一个和业务毫无关系的类创建了mock,Service运行时根本感知不到这个对象,自然走真实单例的逻辑。

2. 只加了注入字段,没改方法内部的真实调用

你展示的改造后Service类中,save方法只留了方法签名public Contract save(Contract contract) {...},如果没有把方法体里原来的ContractDao.getInstance().saveContract(contract)替换成this.contractDao.saveContract(contract),那你新增的contractDao字段从创建到传递全程都没有被业务逻辑使用。方法运行时依然会直接调用静态方法拿真实单例执行,和你传进去的mock没有任何关联。

3. Mockito默认能力边界导致拦截失败

  • 如果使用的是Mockito 5.0之前的版本,没有通过mockmaker-inline开启扩展能力,默认是无法拦截final类、final方法、静态方法的。如果ContractDao.saveContract()被final修饰,默认配置下创建的mock会直接穿透调用真实方法。
  • 如果你在测试初始化时不小心调用了Service的无参构造创建测试对象,而不是用传入mock的带参构造,那么Service内部持有的依然是真实单例,mock自然不会生效。

4. 低概率的连带问题

如果出现过参数不匹配导致stub失效的情况,一般Mockito会返回类型默认值(null、0、false),不会主动触发真实方法,属于最后再排查的选项。比如你用any()匹配入参时,和方法实际入参类型不对应(比如方法入参是基本类型long,用了匹配引用类型的any()),就会出现stub规则没命中的情况,但这种情况不会直接触发真实方法调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 22:54:09