如何SpyOn其他文件本地函数及解决内部调用导出函数SpyOn失效问题
单元测试中SpyOn函数的常见问题解决
嘿,我来帮你搞定这两个单元测试里的spy问题,咱们先从你给出的具体场景入手,再延伸到另一个问题。
问题2:SpyOn同文件中被内部调用的导出函数
你当前遇到的情况是:myFunction里直接调用了同文件的myOtherFunction,但spy检测不到这个调用。问题根源在于:myFunction内部调用的是本地定义的myOtherFunction引用,而你spyOn(helpers, 'myOtherFunction')替换的是模块导出对象上的函数引用——这俩不是同一个引用,所以spy抓不到内部调用。
解决方案分两种:
方案1:修改业务代码,让函数通过模块对象调用
把myFunction里的调用改成引用模块导出的版本,这样spy替换导出对象上的函数后,内部调用就会用被spy的版本:
// File 1 export function myFunction(){ // 用exports或者导入自身模块来调用 return exports.myOtherFunction(); // 或者: // import * as self from './helpers'; // return self.myOtherFunction(); } export function myOtherFunction(){ // do stuff }
这样你的测试代码不需要修改,就能正常检测到调用了。
方案2:不修改业务代码,用工具替换模块内部的本地函数
如果不想动业务代码,可以用rewire(支持Mocha/Jest等)或者Jest的内置能力来直接修改模块内部的本地函数:
- 用
rewire的示例:
// 测试文件 const helpers = rewire('./helpers'); beforeEach(() => { // 替换模块内部的myOtherFunction为spy const myOtherFunctionSpy = jest.fn(); helpers.__set__('myOtherFunction', myOtherFunctionSpy); }); it('should call myOtherFunction', () => { helpers.myFunction(); // 获取被替换的spy并断言 const myOtherFunctionSpy = helpers.__get__('myOtherFunction'); expect(myOtherFunctionSpy).toHaveBeenCalled(); });
- 用Jest的
jest.mock结合requireActual的示例:
// 测试文件 import * as helpers from './helpers'; // 重写模块,保留原始导出,只替换myOtherFunction为spy jest.mock('./helpers', () => { const originalModule = jest.requireActual('./helpers'); return { ...originalModule, myOtherFunction: jest.fn(), // 关键:让myFunction调用的是这个被spy的版本 myFunction: () => originalModule.myFunction.call(helpers) }; }); it('should call myOtherFunction', () => { helpers.myFunction(); expect(helpers.myOtherFunction).toHaveBeenCalled(); });
问题1:SpyOn其他文件中的本地(未导出)函数
如果要spy的是其他文件里没导出的本地函数(比如File1里有个function localFunc() {}没导出,被导出函数调用),核心思路是访问并替换模块内部的私有变量,常用的方法:
- 用
rewire工具:和上面方案2类似,通过__set__方法直接替换模块内部的未导出函数,测试逻辑和之前一致。 - 用Babel插件:比如
babel-plugin-rewire,在编译时给模块添加访问私有变量的方法,用法和rewire类似。 - Jest环境下,可以用
jest.mock完全重写模块,把未导出函数的逻辑替换成spy,同时保留其他导出函数的逻辑。
举个rewire的示例(假设File1有未导出的localFunc被myFunction调用):
// File1 function localFunc() { // do stuff } export function myFunction() { return localFunc(); } // 测试文件 const helpers = rewire('./helpers'); beforeEach(() => { const localFuncSpy = jest.fn(); helpers.__set__('localFunc', localFuncSpy); }); it('should call localFunc', () => { helpers.myFunction(); const localFuncSpy = helpers.__get__('localFunc'); expect(localFuncSpy).toHaveBeenCalled(); });
内容的提问来源于stack exchange,提问作者Samuel Thompson
相关产品推荐
相关产品推荐

