我正在尝试设置 setInterval 调用的测试。 setInterval 总是创建一个新的计时器,因此无论您将 tick() 移动多远,总会出现此消息的错误:
错误:1 个计时器仍在队列中。
如果我用 setInterval 覆盖 setTimeout 函数,则测试将按预期通过。我添加了代码,以允许使用通常设置为 setInterval 的公共(public)属性 myTimerFunc 将其添加到我的 Angular 服务中。测试代码将其设置为setTimeout。
有更好的方法来测试 setInterval 吗?
如果 jasmine 能够忽略队列中的最后一个计时器,那就太好了。然后我就可以在没有额外麻烦的情况下进行测试。
例如,除非取消注释覆盖 setInterval 的行,否则此代码将失败。我不介意在测试代码中执行此操作,但我确实希望避免在正常代码中添加额外的内容只是为了允许此覆盖。
import { fakeAsync, tick } from '@angular/core/testing'
describe('testing setTimeout and setInterval:', () => {
it('setTimeout should work', fakeAsync(() => {
let callback = jasmine.createSpy('setTimeoutCallback')
setTimeout(() => {
callback()
}, 55)
tick(56)
expect(callback).toHaveBeenCalled();
}));
// let setInterval = setTimeout
it('setInterval should work', fakeAsync(() => {
let callback = jasmine.createSpy('setTimeoutCallback')
setInterval(() => {
callback()
}, 55)
tick(56)
expect(callback).toHaveBeenCalled();
}));
})
最佳答案
关于 FakeAsync、flush 的一些理论:这将帮助您理解问题
通过使用 fakeAsync,我们可以确保在测试中做出断言之前所有异步代码都已运行,我们甚至可以对如何在整个测试中提前时间进行微调控制。
- 当测试在 fakeAsync 区域中运行时,我们可以使用两个函数,称为flushMicrotasks和tick。 tick 函数会将时间提前指定的毫秒数,因此 tick(100) 将执行 100 毫秒内发生的任何异步任务。 lushMicrotasks 函数将清除当前队列中的所有微任务。简而言之,如果您不确定时间或依赖于promise/settimeout,那么您需要使用flush()方法。
简化您的问题以了解答案:
it('should test some async code', fakeAsync(() => {
let flag = false;
setTimeout(() => { flag = true; }, 100);
expect(flag).toBe(false); // PASSES
tick(50);
expect(flag).toBe(false); // PASSES
tick(50);
expect(flag).toBe(true); // PASSES
}));
其他可能的替代方案:
it('should test some asynccode', fakeAsync(() => {
let flag = false;
setTimeout(() => { flag = true; }, 100);
expect(flag).toBe(false);
flushMicrotasks();
expect(flag).toBe(true); // FAILS
}));
在您的场景中,
flush() 可以工作
关于javascript - 如何使用 jasmine 测试使用 setInterval 的 Angular 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42957136/