在Jest中是否可以mock同一模块内部被其他函数调用的函数?
问题根因
当前写法失效的核心是foo.ts中foo()调用的是模块内部作用域的原始bar函数引用,而jest.spyOn只能修改导出的模块对象上的bar属性指向,两者不属于同一个引用,因此内部调用不会触发你设置的mock逻辑。
可行解决方法
方案1:调整内部调用指向导出对象(侵入性极低,推荐)
只需修改foo.ts中foo的调用逻辑,让它指向导出的模块对象上的bar,即可兼容原测试代码,TS项目推荐这种写法:
// foo.ts import * as currentModule from './foo' export function bar(){ throw 'not implemented' } export function foo(){ // 调用导出对象上的bar,而非内部作用域的bar return currentModule.bar() }
原测试代码无需修改即可正常运行。
方案2:将函数封装到对象中导出
如果你的函数本身就适合分组封装,可以把相关函数放到统一对象中导出,利用this指向实现可mock:
// foo.ts export const fooUtils = { bar() { throw 'not implemented' }, foo() { return this.bar() } }
测试代码调整为:
// foo.test.ts import { fooUtils } from './foo' test('TODO', () => { jest.spyOn(fooUtils, 'bar').mockReturnValue('quux') expect(fooUtils.foo()).toBe('quux') });
方案3:使用rewire能力修改内部变量(无业务代码侵入)
如果完全不想修改原业务代码,可以借助ts-jest内置的rewire能力直接修改模块内部的bar引用:
- 先在
jest.config.js中开启rewire支持:
module.exports = { // 其余配置保持不变 transform: { '^.+\\.tsx?$': ['ts-jest', { rewire: true }] } }
- 调整测试代码:
// foo.test.ts import * as fooModule from './foo' test('TODO', () => { fooModule.__set__('bar', jest.fn().mockReturnValue('quux')) expect(fooModule.foo()).toBe('quux') })
内容的提问来源于stack exchange,提问作者Andrey Bienkowski
相关产品推荐
相关产品推荐

