You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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的那个导出对象上的函数。

解决步骤:

  1. 修改函数文件的调用方式
    把导入单个函数改成导入整个辅助模块,然后通过模块对象调用函数:

    // 函数文件
    import * as helper from './辅助文件路径';
    
    export async function GetData(user) {
       await helper.checkIfUserAllowed();
       return true;
    }
    

    这样GetData调用的就是模块导出对象上的函数,和你spyOn的是同一个引用,mock才能生效。

  2. 修复mockResolvedValue的用法
    mockResolvedValue必须传入一个参数(哪怕是undefined),调整测试代码:

    it('should return true when user is allowed', async () => {
       spyHelper.mockResolvedValue(undefined); // 传入参数
       const res = await GetData('Brian');
       expect(res).toBeTruthy();
    })
    
  3. 修正第二个测试用例的错误

    • 语法错误: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');
    })
    
  4. 测试后恢复mock(可选)
    为了避免测试用例之间的影响,可以在每个测试后恢复mock:

    afterEach(() => {
       spyHelper.mockRestore();
    })
    

内容的提问来源于stack exchange,提问作者Ghafariz Ainoor Rohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:47:36