我试图从Angular 2中的模拟后端获得单元测试的结果。目前,我们使用fakeAsync
超时来模拟时间的流逝。
当前工作单位测试
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick(3000); //manually specify the waiting time
}));
但是,这意味着我们仅限于手动定义的超时。不是在异步任务完成时。我要做的是让tick()
等到任务完成后再继续测试。
这似乎不按预期工作。
阅读fakeAsync
和tick
答案here解释说:
tick()模拟异步时间的流逝。
我设置了plnkr example来模拟这种情况。
在这里,我们调用getTimeout()
方法,该方法调用具有超时的内部异步任务。在测试中,我们尝试将其包装并在调用tick()
方法后调用getTimeout()
。
counter.ts
getTimeout() {
setTimeout(() => {
console.log('timeout')
},3000)
}
counter.specs.ts
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick();
}));
但是,单元测试失败并出现错误"错误:1个计时器仍在队列中。"
issue here in the angular repo是否与此有关?
是否可以使用tick()
这种方式等待超时功能?或者我可以使用另一种方法吗?
答案 0 :(得分:15)
尝试在测试结束时添加以下功能调用之一或组合:
flush();
flushMicrotasks();
discardPeriodicTasks();
flush
(带有可选的maxTurns参数)也会刷新宏任务。 (Angular测试教程中未提及此功能。)flushMicrotasks
刷新微任务队列。discardPeriodicTasks
取消“周期性定时器仍在队列中”。队列中的计时器不一定表示您的代码有问题。例如,观察当前时间的组件可能会引入此类计时器。如果您使用外部库中的此类组件,则可能还会考虑对它们进行存根而不是“追赶计时器”。
为进一步理解,您可以查看fakeAsync
中zone-testing.js
函数的javascript代码。
答案 1 :(得分:2)
在每个测试的末尾添加:
fixture.destroy();
flush();
答案 2 :(得分:1)
试试这个:
// I had to do this:
it('timeout (fakeAsync/tick)', (done) => {
fixture.whenStable().then(() => {
counter.getTimeout();
tick();
done();
});
});
答案 3 :(得分:0)
我通常在单元测试中使用flushMicrotasks方法与我的服务一起使用。我读过tick()与flushMicrotasks非常相似,但也调用了jasmine tick()方法。
答案 4 :(得分:0)
fakeAsync
的目的是在您的规范内控制时间。 tick
不会等待任何时间,因为它是用于模拟时间流逝的同步功能。如果要等到异步功能完成,则需要使用async
和whenStable
,但是,在您的示例中,规范需要3秒钟才能通过,因此我不会建议这个。
counter.spec.ts 失败的原因是您仅模拟了0秒的经过(通常用于表示事件循环的下一个滴答声)。因此,当规范完成时,仍然有模拟计时器处于活动状态,这会使整个规范失效。通知您模拟了超时,并且未处理,它实际上在正常工作。
基本上,我认为您正在尝试以不打算使用的方式使用fakeAsync
和tick
。如果您需要按照建议的方法测试超时,最简单的方法就是自己模拟setTimeout
函数,以便无论使用什么时间,都可以调用该方法。
已编辑 我遇到了一个相关的问题,我想清除计时器,由于它不是要测试的部分,所以我不在乎它花了多长时间。我尝试过:
tick(Infinity);
曾工作过,但超级hacky。我最终选择了
discardPeriodicTasks();
我的所有计时器都清除了。
答案 5 :(得分:0)
对我来说,上述所有操作均无济于事,但在测试代码中两次调用tick(<async_time>)
。
到目前为止,我的解释是:对于每个异步调用,您都需要一个/自己的tick()调用。
此后我有一个.pipe(debounceTime(500))
和一个timer(500).subscribe(..)
,这有所帮助:
tick(500);
tick(500);
答案 6 :(得分:-1)
异步
test.service.ts
export class TestService {
getTimeout() {
setTimeout(() => { console.log("test") }, 3000);
}
}
test.service.spec.ts
import { TestBed, async } from '@angular/core/testing';
describe("TestService", () => {
let service: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TestService],
});
service = TestBed.get(TestService);
});
it("timeout test", async(() => {
service.getTimeout();
});
});
伪异步
test.service.ts
export class TestService {
readonly WAIT_TIME = 3000;
getTimeout() {
setTimeout(() => { console.log("test") }, this.WAIT_TIME);
}
}
test.service.spec.ts
import { TestBed, fakeAsync } from '@angular/core/testing';
describe("TestService", () => {
let service: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TestService],
});
service = TestBed.get(TestService);
});
it("timeout test", fakeAsync(() => {
service.getTimeout();
tick(service.WAIT_TIME + 10);
});
});