在前端开发中,我们经常需要使用 setTimeout
和setInterval
待定时器来执行一些异步操作,但当进行单元测试时, 这样的异步操作会导致测试的不确定性,因为测试的结果取决于待定时器何时被执行,而测试端无法控制待定时器的执行时间。 Jest提供了一些API来帮助我们在测试时模拟这些待定时器。
Jest 提供的 mock 定时器 API
Jest 提供了两个事件轮询的 mock API:jest.useFakeTimers()
和 jest.runAllTimers()
。 jest.useFakeTimers()
主要用于直接替换 setInterval、setTimeout 和 clearTimeout / clearInterval,使得在我们不必等待实际速度而直接运行测试的情况下,重建我们的循环事件和时间逻辑。可以调用 jest.runAllTimers()
来强制执行所有待定的定时器或者 jest.runOnlyPendingTimers()
来只执行待执行的定时器。
当使用 jest.useFakeTimers()
后,测试时周期事件轮询的定时器不再是真正的定时器,而是被完全控制的事件轮询模拟器。那么如何模拟setTimeout
和setInterval
呢?
模拟 setTimeout
我们可以使用 jest.runAllTimers()
来模拟 setTimeout
。它会立即将所有待执行的定时器达成的效果都执行,因此我们可以通过向 setTimeout
传递一个函数作为回调,然后手动的调用 jest.runAllTimers()
来立即执行定时器中的所有回调函数。
比如设在测试代码中,有一个函数 delayAndReturn
,它将在两秒后返回一个数字 1。函数实现如下:
function delayAndReturn() { setTimeout(() => { return 1; }, 2000); }
在测试代码中,我们可以使用以下方式来测试该函数:
test('delayAndReturn returns after 2 seconds', () => { jest.useFakeTimers(); const returnValue = delayAndReturn(); expect(returnValue).toBeUndefined(); jest.runAllTimers(); expect(returnValue).toBe(1); });
模拟 setInterval
我们也可以使用 jest.runOnlyPendingTimers()
命令来模拟 setInterval
。它会只执行当前待执行的定时器,而不是所有。
比如设在测试代码中,有一个函数 logMessage
,它将每秒 log 一条 message。函数实现如下:
function logMessage() { setInterval(() => { console.log('hello world'); }, 1000); }
在测试代码中,我们可以使用以下方式来测试该函数:
-- -------------------- ---- ------- ---------------- ---- - ------- ----- -------- -- -- - --------------------- ----- ---------- - ------------------- ------- ----- ------------ - ------------- ------------------------------------------ ---------------------------- -------------------------------------------- ---------------------------- -------------------------------------------- --------------- ---
总结
Jest 提供了事件轮询 mock API 来模拟待定时器,帮助我们在使用待定时器时进行单元测试。在测试中,我们使用jest.useFakeTimers
来替换setTimeout
和 setInterval
,使用jest.runAllTimers
强制执行所有待执行的定时器,以执行回调函数,使用 jest.runOnlyPendingTimers()
来强制执行所有待执行的定时器,以确保函数能够按预期工作。加入这些应该让你能够更方便地测试异步代码,并且保证它们能够在团队内部和客户内部进行工作。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/647ea88448841e9894e5c2f9