Jest中spyOn调用mockImplementation仍执行原方法的原因咨询
问题根本原因
第一种测试写法mock的实例和业务代码实际使用的实例不是同一个对象,mock自然不会生效。
执行逻辑拆解
- 业务代码的实例初始化在模块加载阶段就已完成:当你在测试代码中引入业务模块时,业务模块顶层的
const emailModule = new SomeEmailModule()会立刻执行,生成的实例会一直保存在业务模块的作用域中,sendEmail函数后续调用的永远是这个提前生成的实例的send方法。 - 第一种测试写法的问题:你在测试用例内部执行
const emailModule = new SomeEmailModule()是新生成了另一个完全独立的实例,你用jest.spyOn修改的是这个新实例自身的send方法,对业务模块里早就创建完成的旧实例没有任何影响,所以实际执行时还是走原生方法逻辑。
后两种写法生效的底层逻辑
JS 中类的实例方法默认挂载在构造函数的原型对象上,只要实例自身没有单独重写这个方法,调用时会沿着原型链向上查找到构造函数prototype上的对应方法。
- 直接修改
SomeEmailModule.prototype.send相当于修改了所有实例共享的方法源头,不管是业务代码提前生成的旧实例,还是后续新生成的实例,调用send时都会走到你mock的版本。 - 用
jest.spyOn(SomeEmailModule.prototype, 'send')(注:你写法里的spyOne是笔误,正确为spyOn)的逻辑和直接修改原型一致,只是jest封装了备份原始方法、测试结束后可一键还原的能力,底层都是修改原型上的公共方法。
补充:其他可行的mock方案
如果不想修改原型,也可以直接mock整个SomeEmailModule的导出,让所有实例化操作都返回带mock方法的对象:
const mockSend = jest.fn() jest.mock('SomeEmailModule', () => { return jest.fn().mockImplementation(() => ({ send: mockSend })) })
内容的提问来源于stack exchange,提问作者Beginner
相关产品推荐
相关产品推荐

