Jest无法识别Spy已调用的技术问题求助
解决Jest中Promise回调里Spy函数未被正确断言的问题
你遇到的核心问题是Jest在异步代码(Promise的then回调)执行完成前就跑完了断言。sendSpy是同步触发的,所以它的断言能顺利通过;但sendCallbackSpy是在Promise的微任务队列里执行的,测试函数同步执行完所有断言后,微任务才会被处理——此时断言已经结束,自然会判定sendCallbackSpy未被调用。
常见解决方案(附代码示例)
假设你的业务代码大致是这样的:
// 业务代码示例 const sendSpy = jest.fn(() => Promise.resolve('success')); const sendCallbackSpy = jest.fn(); function executeTask() { sendSpy().then(() => { sendCallbackSpy(); // 这个Spy在测试里没被断言到 }); }
方法1:让测试函数返回Promise
直接返回包含断言的Promise,Jest会自动等待这个Promise完成后再结束测试:
test('should trigger sendCallbackSpy after sendSpy resolves', () => { executeTask(); expect(sendSpy).toHaveBeenCalled(); // 返回Promise,等待sendSpy的异步操作完成后再断言 return sendSpy.mock.results[0].value.then(() => { expect(sendCallbackSpy).toHaveBeenCalled(); }); });
方法2:使用async/await(最简洁推荐)
如果可以修改业务函数让它返回内部的Promise,直接await即可:
// 先修改业务函数,返回Promise function executeTask() { return sendSpy().then(() => { sendCallbackSpy(); }); } // 测试用例 test('should trigger sendCallbackSpy after sendSpy resolves', async () => { await executeTask(); expect(sendSpy).toHaveBeenCalled(); expect(sendCallbackSpy).toHaveBeenCalled(); });
如果不能修改业务函数,也可以直接await Spy返回的Promise:
test('should trigger sendCallbackSpy after sendSpy resolves', async () => { executeTask(); expect(sendSpy).toHaveBeenCalled(); await sendSpy.mock.results[0].value; // 等待Promise完成 expect(sendCallbackSpy).toHaveBeenCalled(); });
方法3:使用Jest的done回调
通过done参数手动告诉Jest什么时候结束测试:
test('should trigger sendCallbackSpy after sendSpy resolves', (done) => { executeTask(); expect(sendSpy).toHaveBeenCalled(); // 监听sendCallbackSpy的调用,一旦触发就完成测试 sendCallbackSpy.mockImplementation(() => { expect(sendCallbackSpy).toHaveBeenCalled(); done(); }); // 别忘了捕获Promise错误,避免测试超时 sendSpy.mock.results[0].value.catch(done); });
关于添加console.log后“看似正常”的说明
你提到加了console.log后情况有变化,这只是偶然的伪修复:console.log是同步操作,它会占用一点执行时间,让事件循环有机会提前处理微任务(也就是then回调),但这种方式完全不可靠,不能作为正式解决方案。
内容的提问来源于stack exchange,提问作者Max Millington
相关产品推荐
相关产品推荐

