如何使用假计时器测试递归的异步 JavaScript 函数?
How do I test a recursive, asynchronous JavaScript function using fake timers?
我有一个基本的递归函数,它在执行时可以正常工作。我想使用 Sinon 的假计时器来测试每个执行阶段的功能。
但是,假计时器似乎只适用于递归函数的第一次调用。
我很好奇是否有人可以帮助弄清楚如何让假定时器一直工作。
示例:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function ensureCount(count, { attempt, delay }) {
attempt = attempt || 0
console.log('Attempt', attempt)
if (attempt === count) {
return
}
await wait(delay)
await ensureCount(count, { attempt: attempt + 1, delay })
}
像这样测试(在this article的帮助下):
it('retries after a given delay', function() {
const clock = sinon.useFakeTimers()
const promise = ensureCount(2, { delay: 200 })
clock.tick(200)
// Make some assertions.
clock.tick(200)
// Make some assertions.
clock.tick(200)
// Make some assertions.
return promise
})
预期的控制台输出(这是没有假计时器时发生的情况):
Attempt 0
Attempt 1
Attempt 2
✔ retries after a given delay (405ms)
实际的控制台输出(发生在假计时器上):
Attempt 0
Attempt 1
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
问题:
有没有办法让假计时器应用于递归调用的每一步,而不仅仅是第一步?
原来Sinon为此提供了一个我没见过的.tickAsync()
函数。 (感谢 )。
此代码解决了问题:
it('retries after a given delay', async () => {
const clock = sinon.useFakeTimers()
ensureCount(2, { delay: 200 })
await clock.tickAsync(200)
// Make some assertions.
await clock.tickAsync(200)
// Make some assertions.
await clock.tickAsync(200)
// Make some assertions.
clock.restore()
})
我有一个基本的递归函数,它在执行时可以正常工作。我想使用 Sinon 的假计时器来测试每个执行阶段的功能。
但是,假计时器似乎只适用于递归函数的第一次调用。
我很好奇是否有人可以帮助弄清楚如何让假定时器一直工作。
示例:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function ensureCount(count, { attempt, delay }) {
attempt = attempt || 0
console.log('Attempt', attempt)
if (attempt === count) {
return
}
await wait(delay)
await ensureCount(count, { attempt: attempt + 1, delay })
}
像这样测试(在this article的帮助下):
it('retries after a given delay', function() {
const clock = sinon.useFakeTimers()
const promise = ensureCount(2, { delay: 200 })
clock.tick(200)
// Make some assertions.
clock.tick(200)
// Make some assertions.
clock.tick(200)
// Make some assertions.
return promise
})
预期的控制台输出(这是没有假计时器时发生的情况):
Attempt 0
Attempt 1
Attempt 2
✔ retries after a given delay (405ms)
实际的控制台输出(发生在假计时器上):
Attempt 0
Attempt 1
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
问题:
有没有办法让假计时器应用于递归调用的每一步,而不仅仅是第一步?
原来Sinon为此提供了一个我没见过的.tickAsync()
函数。 (感谢
此代码解决了问题:
it('retries after a given delay', async () => {
const clock = sinon.useFakeTimers()
ensureCount(2, { delay: 200 })
await clock.tickAsync(200)
// Make some assertions.
await clock.tickAsync(200)
// Make some assertions.
await clock.tickAsync(200)
// Make some assertions.
clock.restore()
})