如何使用Jest模拟异步函数延迟并测试异步函数顺序执行逻辑
Jest测试异步函数调用顺序的正确姿势
你的测试核心问题在于:Jest的jest.runAllTimers()只会触发宏任务(比如setTimeout),但await后的Promise回调属于微任务,不会被自动执行;再加上测试没有等待异步流程完成,导致断言时机不对。
以下是修正后的完整测试代码:
test('Should not call second function until first function resolved', async () => { jest.useFakeTimers(); const spyOnFuncA = jest.spyOn(module2, 'funcA').mockImplementation(() => new Promise(resolve => setTimeout(resolve, 1000)) ); const spyOnFuncB = jest.spyOn(module2, 'funcB').mockImplementation(); // 启动异步函数但不等待 mainFunc(); // 第一个断言:funcA已调用,funcB未调用 expect(spyOnFuncA).toHaveBeenCalled(); expect(spyOnFuncB).not.toHaveBeenCalled(); // 快进所有定时器(触发funcA的Promise resolve) jest.runAllTimers(); // 等待微任务队列清空(让await funcA()后的代码执行) await Promise.resolve(); // 第二个断言:funcB已被调用 expect(spyOnFuncB).toHaveBeenCalled(); // 清理mock,避免影响其他测试 spyOnFuncA.mockRestore(); spyOnFuncB.mockRestore(); jest.useRealTimers(); });
关键要点说明
- 测试函数必须标记为async:因为需要等待微任务完成后再做断言
- 等待微任务:
await Promise.resolve()会让JavaScript引擎先处理完当前所有微任务(也就是await funcA()之后的funcB()调用逻辑) - 清理mock和定时器:测试结束后恢复原始函数和真实定时器,防止污染其他测试用例
- mock简化:不需要给funcA的mock加async关键字,直接返回Promise即可,效果一致
内容的提问来源于stack exchange,提问作者tosh
相关产品推荐
相关产品推荐

