Javascript Jest模拟计时器不能按预期异步工作;如何使这次考试通过?
我正在尝试测试一个队列组件,它可以进行调用并处理大量调度。我想用一个模拟api来测试它,api响应会像在现实生活中一样延迟,但我想用模拟计时器来模拟时间的流逝。在下面的简单示例中,被测试的对象是调用者对象Javascript Jest模拟计时器不能按预期异步工作;如何使这次考试通过?,javascript,typescript,unit-testing,timer,jestjs,Javascript,Typescript,Unit Testing,Timer,Jestjs,我正在尝试测试一个队列组件,它可以进行调用并处理大量调度。我想用一个模拟api来测试它,api响应会像在现实生活中一样延迟,但我想用模拟计时器来模拟时间的流逝。在下面的简单示例中,被测试的对象是调用者对象 function mockCall(): Promise<string> { return new Promise<string>(resolve => setTimeout(() => resolve("success"), 20)); } co
function mockCall(): Promise<string> {
return new Promise<string>(resolve => setTimeout(() => resolve("success"), 20));
}
const callReceiver = jest.fn((result: string) => { console.log(result)});
class Caller {
constructor(call: () => Promise<string>,
receiver: (result: string) => void) {
call().then(receiver);
}
}
it("advances mock timers correctly", () => {
jest.useFakeTimers();
new Caller(mockCall, callReceiver);
jest.advanceTimersByTime(50);
expect(callReceiver).toHaveBeenCalled();
});
函数mockCall():Promise{
返回新承诺(resolve=>setTimeout(()=>resolve(“success”),20);
}
const callReceiver=jest.fn((结果:string)=>{console.log(结果)});
类调用者{
构造函数(调用:()=>Promise,
接收方:(结果:字符串)=>void){
调用(),然后调用(接收方);
}
}
它(“正确推进模拟计时器”,()=>{
开玩笑。使用faketimers();
新呼叫者(mockCall、callReceiver);
开玩笑提前计时(50);
expect(callReceiver).toHaveBeenCalled();
});
我认为这个测试应该通过,但是在定时器提前之前,会对expect
进行评估,因此测试失败。如何编写此测试以使其通过
顺便说一句,如果我使用实时计时器并将
expect
延迟20毫秒以上,这个测试确实通过了,但我特别感兴趣的是使用假计时器并用代码推进时间,而不是等待实时过去 您可以通过将承诺返回给jest,使测试工作正常,否则您的测试方法的执行已经完成,并且不会等待承诺实现
function mockCall() {
return new Promise(resolve => setTimeout(() => resolve('success'), 20));
}
const callReceiver = jest.fn((result) => { console.log(result); });
class Caller {
constructor(callee, receiver) {
this.callee = callee;
this.receiver = receiver;
}
execute() {
return this.callee().then(this.receiver);
}
}
describe('my test suite', () => {
it('advances mock timers correctly', () => {
jest.useFakeTimers();
const caller = new Caller(mockCall, callReceiver);
const promise = caller.execute();
jest.advanceTimersByTime(50);
return promise.then(() => {
expect(callReceiver).toHaveBeenCalled();
});
});
});
您可以通过将承诺返回给jest来实现测试,否则测试方法的执行已经完成,并且不会等待承诺的实现
function mockCall() {
return new Promise(resolve => setTimeout(() => resolve('success'), 20));
}
const callReceiver = jest.fn((result) => { console.log(result); });
class Caller {
constructor(callee, receiver) {
this.callee = callee;
this.receiver = receiver;
}
execute() {
return this.callee().then(this.receiver);
}
}
describe('my test suite', () => {
it('advances mock timers correctly', () => {
jest.useFakeTimers();
const caller = new Caller(mockCall, callReceiver);
const promise = caller.execute();
jest.advanceTimersByTime(50);
return promise.then(() => {
expect(callReceiver).toHaveBeenCalled();
});
});
});
原因是
mockCall
仍然返回承诺,即使在模拟计时器之后。因此,call()。然后()
将作为下一个微任务执行。要推进执行,您也可以将expect
包装到microtask中:
it("advances mock timers correctly", () => {
jest.useFakeTimers();
new Caller(mockCall, callReceiver);
jest.advanceTimersByTime(50);
return Promise.resolve().then(() => {
expect(callReceiver).toHaveBeenCalled()
});
});
当心不要收回这个承诺,这样玩笑会一直等到它完成。对我来说,使用async/await会更好:
it("advances mock timers correctly", async () => {
jest.useFakeTimers();
new Caller(mockCall, callReceiver);
jest.advanceTimersByTime(50);
await Promise.resolve();
expect(callReceiver).toHaveBeenCalled();
});
顺便说一句,每次模拟返回的Promise
(例如fetch
)时都会发生同样的事情-您将需要像使用假计时器一样推进微任务队列
有关微任务/宏任务队列的详细信息:
Jest repo已公开提议以更明确的方式处理未决承诺,但迄今为止还没有ETA。原因是
mockCall
仍然返回承诺,即使在您模拟计时器之后。因此,call()。然后()
将作为下一个微任务执行。要推进执行,您也可以将expect
包装到microtask中:
it("advances mock timers correctly", () => {
jest.useFakeTimers();
new Caller(mockCall, callReceiver);
jest.advanceTimersByTime(50);
return Promise.resolve().then(() => {
expect(callReceiver).toHaveBeenCalled()
});
});
当心不要收回这个承诺,这样玩笑会一直等到它完成。对我来说,使用async/await会更好:
it("advances mock timers correctly", async () => {
jest.useFakeTimers();
new Caller(mockCall, callReceiver);
jest.advanceTimersByTime(50);
await Promise.resolve();
expect(callReceiver).toHaveBeenCalled();
});
顺便说一句,每次模拟返回的Promise
(例如fetch
)时都会发生同样的事情-您将需要像使用假计时器一样推进微任务队列
有关微任务/宏任务队列的详细信息:
Jest repo已公开提议以更明确的方式处理未决承诺,但目前还没有ETA