如何在Jest中模拟同模块内被测试函数调用的方法
解决Jest无法模拟同模块内函数调用的问题
你的核心问题是:同模块内的methodA直接调用本地的methodB函数,而Jest只能模拟模块导出的函数引用,所以你之前的模拟操作根本没拦截到methodA里的实际调用。
第一步:修复模块内的调用逻辑
修改methods.js,让methodA通过模块的导出对象来调用methodB,而不是直接调用本地函数:
// @/domains/methods.js export async function methodA() { // 改为通过exports对象调用methodB(CommonJS风格) const response = await exports.methodB(); return response.length ? 'something' : 'else'; } export async function methodB() { const array = await getData(); // 数据库/API调用 return array; // 修正原代码的语法错误:array[] 是无效写法 }
如果是纯ES模块,也可以用自身导入的方式:
// @/domains/methods.js import * as self from './methods'; export async function methodA() { const response = await self.methodB(); return response.length ? 'something' : 'else'; } export async function methodB() { const array = await getData(); return array; }
第二步:使用Jest模拟并测试
现在你之前尝试的两种模拟方式都能生效了,下面是两种可行的测试写法:
写法1:使用jest.spyOn监视并模拟
import * as myModule from '@/domains/methods'; describe('method testing', () => { it('返回"else"当methodB返回空数组时', async () => { // 监视methodB并模拟它返回空数组 const mockMethodB = jest.spyOn(myModule, 'methodB').mockResolvedValue([]); const response = await myModule.methodA(); expect(response).toBe('else'); expect(mockMethodB).toHaveBeenCalled(); // 测试后恢复原方法,避免影响其他用例 mockMethodB.mockRestore(); }); });
写法2:模拟整个模块并保留原methodA
// 先模拟模块,再导入 jest.mock('@/domains/methods', () => { const originalModule = jest.requireActual('@/domains/methods'); return { ...originalModule, methodB: jest.fn().mockResolvedValue([]) }; }); import * as myModule from '@/domains/methods'; describe('method testing', () => { it('返回"else"当methodB返回空数组时', async () => { const response = await myModule.methodA(); expect(response).toBe('else'); expect(myModule.methodB).toHaveBeenCalled(); }); });
关键说明
为什么之前的模拟无效?因为原代码里methodA调用的是模块内部定义的methodB函数,和你通过import * as myModule拿到的导出引用不是同一个。只有让methodA调用导出的methodB引用,Jest的模拟才能拦截到这个调用链路。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

