如何解决Jest中模拟内部异步函数时mockResolvedValue失效问题?
问题:无法模拟异步函数,
mockResolvedValue无效但mockImplementation有效 我知道这个问题可能被提过很多次,但我的情况有点不一样——我没法模拟待测试函数内部调用的异步函数,试了mockImplementation、mockResolvedValue等方法,前者有效后者却不行。下面是我的代码结构,麻烦帮我看看问题出在哪?
涉及三个文件:测试文件、函数文件、辅助文件
辅助文件
export async function checkIfUserAllowed() { if (!allowed) throw new Error('Not Allowed') }
函数文件
export async function GetData(user) { await checkIfUserAllowed(); return true; }
测试文件
const spyHelper = jest.spyOn(helper, 'checkIfUserAllowed') describe('when user getting data', () => { it('should return data', async () => { spyHelper.mockResolvedValue() // <-- 此方法无效,仍调用真实函数 const res = await GetData('Brian') expect(res).toBeTruthy(); }) it('should return data', async () => { spyHelper.mockImplementation(() => throw new Error('Not Allowed')) // <-- 此方法有效 const res = await GetData('Brian') expect(res).toBeFalsy(); }) })
问题原因及解决办法
核心问题:模块引用方式不对
你在GetData里直接调用的checkIfUserAllowed是模块导入的本地变量,而jest.spyOn mock的是辅助模块导出的函数对象。两者不是同一个引用,所以mockResolvedValue无法生效——因为GetData根本没用到你mock的那个导出对象上的函数。
解决步骤:
修改函数文件的调用方式
把导入单个函数改成导入整个辅助模块,然后通过模块对象调用函数:// 函数文件 import * as helper from './辅助文件路径'; export async function GetData(user) { await helper.checkIfUserAllowed(); return true; }这样
GetData调用的就是模块导出对象上的函数,和你spyOn的是同一个引用,mock才能生效。修复
mockResolvedValue的用法mockResolvedValue必须传入一个参数(哪怕是undefined),调整测试代码:it('should return true when user is allowed', async () => { spyHelper.mockResolvedValue(undefined); // 传入参数 const res = await GetData('Brian'); expect(res).toBeTruthy(); })修正第二个测试用例的错误
- 语法错误:
mockImplementation里的抛出错误需要用大括号包裹 - 断言逻辑错误:
GetData会因为checkIfUserAllowed抛出错误而reject,要捕获错误而非判断返回值:
it('should throw error when user is not allowed', async () => { spyHelper.mockImplementation(() => { throw new Error('Not Allowed') }); await expect(GetData('Brian')).rejects.toThrow('Not Allowed'); })- 语法错误:
测试后恢复mock(可选)
为了避免测试用例之间的影响,可以在每个测试后恢复mock:afterEach(() => { spyHelper.mockRestore(); })
内容的提问来源于stack exchange,提问作者Ghafariz Ainoor Rohan
相关产品推荐
相关产品推荐

