【发布时间】:2019-01-18 14:39:35
【问题描述】:
考虑这个函数
function startTimerWithAsyncCallback(
firstAsyncFunction,
secondAsyncFunction,
thirdAsyncFunction,
millis,
) {
setTimeout(async () => {
await firstAsyncFunction();
await secondAsyncFunction();
await thirdAsyncFunction();
}, millis);
}
我想测试 3 个异步函数是否在超时后被调用,使用开玩笑的假计时器。
test('fake timers', () => {
jest.useFakeTimers();
const firstAsyncFunction = jest.fn();
const secondAsyncFunction = jest.fn();
const thirdAsyncFunction = jest.fn();
startTimerWithAsyncCallback(
firstAsyncFunction,
secondAsyncFunction,
thirdAsyncFunction,
1000,
);
jest.advanceTimersByTime(2000);
expect(firstAsyncFunction).toHaveBeenCalled();
expect(secondAsyncFunction).toHaveBeenCalled(); // FAILS HERE !
expect(thirdAsyncFunction).toHaveBeenCalled();
});
通过此测试,第一个异步函数处于挂起状态,并且不会调用下一个异步函数。在进行断言之前,我没有找到一种方法来告诉:“等待 setTimeout 的回调完成”
我想出了一个解决方法,即恢复真实计时器并在断言之前等待 0 毫秒。
test('fake timers and restore real timers', async () => {
jest.useFakeTimers();
const firstAsyncFunction = jest.fn();
const secondAsyncFunction = jest.fn();
const thirdAsyncFunction = jest.fn();
startTimerWithAsyncCallback(
firstAsyncFunction,
secondAsyncFunction,
thirdAsyncFunction,
1000,
);
jest.advanceTimersByTime(2000);
expect(firstAsyncFunction).toHaveBeenCalled();
await waitAsyncFunctionsToComplete(); // WORKAROUND
expect(secondAsyncFunction).toHaveBeenCalled();
expect(thirdAsyncFunction).toHaveBeenCalled();
});
async function waitAsyncFunctionsToComplete() {
jest.useRealTimers();
await delay(0);
jest.useFakeTimers();
}
async function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
有没有更合适的方法来实现这一点?
【问题讨论】:
-
不方便测试的原因是
startTimerWithAsyncCallback()无法知道它何时完成。如果这个函数返回一个你可以用来知道它何时完成的承诺会更简洁。 -
@MarkMeyer 我明白你的意思。然而,在我最初的问题中,我使用
setInterval而不是setTimeout来定期运行asyncCallback。也许我应该重新考虑我的设计......
标签: javascript node.js unit-testing jestjs