我正在尝试设置setInterval调用的测试。 setInterval总是创建一个新的计时器,所以无论你向前移动tick(),这条消息总会出错:
错误:1个计时器仍然在队列中。
如果我用setInterval覆盖setTimeout函数,则测试按预期传递。我已经使用通常设置为setInterval的公共属性myTimerFunc添加了代码以允许我的角度服务。测试代码将其设置为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();
}));
})
答案 0 :(得分:0)
如果你将setInterval
包装在服务中,你可以模拟服务,一切都是确定性的,没有任何副作用。基本上你只是做像
class IntervalService {
setInterval(callback: () => void, interval: number) {
return setInterval(callback, interval);
}
clearInterval(intervalId: number) {
clearInterval(intervalId);
}
}
你可以模仿它的方式是做类似的事情
class MockIntervalService {
callback;
setInterval(callback: () => any, interval: number) {
this.callback = callback;
return 1;
}
clearInterval(interval: number) {
callback = undefined;
}
tick() {
callback();
}
}
然后在测试中,您可以通过在模拟服务上调用tick
来控制间隔。最好的部分是一切都是同步的,使测试更容易推理。
注入服务需要额外的工作,但我不认为这是一个很大的负担。
答案 1 :(得分:0)
有关FakeAsync的一些理论,刷新:这将帮助您理解问题
通过使用fakeAsync,我们可以确保在测试中声明之前,所有异步代码都已运行,甚至可以更好地控制我们如何延长测试时间。
简化您的问题以了解答案:
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()将起作用