Javascript Angular 2 fakeAsync 在使用 tick() 的函数中等待超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43060886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 2 fakeAsync waiting for timeout in a function using tick()?
提问by nipuna777
I'm trying to get the results from a mock backend in Angular 2 for unit testing. Currently, we are using fakeAsyncwith a timeout to simulate the passing of time.
我正在尝试从 Angular 2 中的模拟后端获取结果以进行单元测试。目前,我们正在使用fakeAsync超时来模拟时间的流逝。
current working unit test
当前工作单元测试
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick(3000); //manually specify the waiting time
}));
But, this means that we are limited to a manually defined timeout. Not when the async task is completed. What I'm trying to do is getting tick()to wait until the task is completed before continuing with the test.
但是,这意味着我们仅限于手动定义的超时。不是在异步任务完成时。我要做的是tick()等到任务完成后再继续测试。
This does not seem to work as intended.
这似乎没有按预期工作。
Reading up on the fakeAsyncand tickthe answer hereexplains that:
阅读fakeAsync和这里tick的答案解释说:
tick() simulates the asynchronous passage of time.
tick() 模拟时间的异步流逝。
I set up a plnkr examplesimulating this scenario.
我设置了一个plnkr 示例来模拟这种情况。
Here, we call the getTimeout()method which calls an internal async task that has a timeout. In the test, we try wrapping it and calling tick()after calling the getTimeout()method.
在这里,我们调用getTimeout()调用具有超时的内部异步任务的方法。在测试中,我们尝试将其封装起来,调用方法tick()后再调用getTimeout()。
counter.ts
计数器.ts
getTimeout() {
setTimeout(() => {
console.log('timeout')
},3000)
}
counter.specs.ts
counter.specs.ts
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick();
}));
But, the unit test fails with the error "Error: 1 timer(s) still in the queue."
但是,单元测试失败并显示错误“错误:1 个计时器仍在队列中”。
Does the issue here in the angular repohave anything to do with this?
Is it possible to use tick()this way to wait for a timeout function? Or is there another approach that I can use?
是否可以使用tick()这种方式来等待超时功能?或者我可以使用另一种方法吗?
回答by nephiw
The purpose of fakeAsyncis to control time within your spec. tickwill not wait for any time as it is a synchronous function used to simulate the passage of time. If you want to wait until the asynchronous function is complete, you are going to need to use asyncand whenStable, however, in your example, the spec will take 3 seconds to pass so I wouldn't advise this.
目的fakeAsync是在您的规范内控制时间。tick不会等待任何时间,因为它是用于模拟时间流逝的同步功能。如果您想等到异步函数完成,您将需要使用asyncand whenStable,但是,在您的示例中,规范将需要 3 秒才能通过,因此我不建议这样做。
The reason why the counter.spec.tsis failing is that you have only simulated the passage of 0 seconds (typically used to represent the next tick of the event loop). So when the spec completes, there are still mocked timers active and that fails the whole spec. It is actually working properly by informing you that a timeout has been mocked an is unhandled.
counter.spec.ts失败的原因是您只模拟了 0 秒的通过(通常用于表示事件循环的下一个滴答声)。因此,当规范完成时,仍然有模拟计时器处于活动状态,并且整个规范都失败了。通过通知您超时已被模拟并且未处理,它实际上可以正常工作。
Basically, I think you are attempting to use fakeAsyncand tickin ways for which they were not intended to be used. If you need to test a timeout the way that you have proposed, the simplest way would be to mock the setTimeoutfunction yourself so that, regardless of the time used, you can just call the method.
基本上,我认为你正试图利用fakeAsync并tick为他们并不打算使用方式。如果您需要按照您建议的方式测试超时,最简单的方法是自己模拟该setTimeout函数,以便无论使用的时间如何,您都可以调用该方法。
EDITEDI ran into a related issue where I wanted to clear the timers, and since it was not the part under test, I didn't care how long it took. I tried:
编辑我遇到了一个相关的问题,我想清除计时器,因为它不是被测部分,所以我不在乎花了多长时间。我试过:
tick(Infinity);
Which worked, but was super hacky. I ended up going with
哪个有效,但超级hacky。我最终去了
discardPeriodicTasks();
And all of my timers were cleared.
我所有的计时器都被清除了。
回答by dangchithao
At the end of each test add:
在每个测试的末尾添加:
fixture.destroy();
flush();
回答by SrAxi
回答by user11883568
Try to add one or a combination of the following function calls to the end of your test:
尝试将以下函数调用的一个或组合添加到测试的末尾:
flush();
flushMicrotasks();
discardPeriodicTasks();
flush(with optional maxTurns parameter) also flushes macrotasks. (This function is not mentionned in the Angular testing tutorial.)flushMicrotasksflushes the microtask queue.discardPeriodicTaskscancels "peridodic timer(s) still in the queue".
flush(带有可选的 maxTurns 参数)也会刷新宏任务。(Angular 测试教程中没有提到这个功能。)flushMicrotasks刷新微任务队列。discardPeriodicTasks取消“仍在队列中的周期计时器”。
Timers in the queue do not necessarily mean that there's a problem with your code. For example, components that observe the current time may introduce such timers. If you use such components from a foreign library, you might also consider to stub them instead of "chasing timers".
队列中的计时器并不一定意味着您的代码存在问题。例如,观察当前时间的组件可能会引入这样的计时器。如果您使用来自外部库的此类组件,您可能还会考虑存根它们而不是“追逐计时器”。
For further understanding you may look at the javascript code of the fakeAsyncfunction in zone-testing.js.
如需进一步了解,你可以看看的JavaScript代码fakeAsync的功能zone-testing.js。
回答by christo8989
Async
异步
test.service.ts
测试服务.ts
export class TestService {
getTimeout() {
setTimeout(() => { console.log("test") }, 3000);
}
}
test.service.spec.ts
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();
});
});
Fake Async
假异步
test.service.ts
测试服务.ts
export class TestService {
readonly WAIT_TIME = 3000;
getTimeout() {
setTimeout(() => { console.log("test") }, this.WAIT_TIME);
}
}
test.service.spec.ts
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);
});
});
回答by Nick
I normally use the flushMicrotasks method in my unit tests for use with my services. I had read that tick() is very similar to flushMicrotasks but also calls the jasmine tick() method.
我通常在我的单元测试中使用 flushMicrotasks 方法来与我的服务一起使用。我读过 tick() 与 flushMicrotasks 非常相似,但也调用 jasmine tick() 方法。

