为何模拟单例依赖时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
相关产品推荐
相关产品推荐

