我有一个幻灯片放映组件,它有一个幻灯片对象的输入数组,并且只要在slide.time
中定义了它们,就会显示每个对象。还有两个点击它们的按钮必须滑动到下一个项目并重置计时器。为了完成这项工作,我使用了这样的Observable:
/**
* a "SUBJECT" for pausing(restarting) the slider's auto-slide on user's click on left and right arrows
* @type {Subject}
*/
private pauser = new Subject();
/**
* the main observable for timer (before adding the pause/reset option)
* @type {Observable<T>}
*/
private source = Observable
.interval(1000)
.timeInterval()
.map(function (x) { /*return x.value + ':' + x.interval;*/ return x })
.share();
/**
* the final timer, which can be paused
* @type {Observable<R>}
*/
private pausableSource = this.pauser.switchMap(paused => paused ? Observable.never() : this.source);
/**
* the subscription to the timer which is assigned at OnInit hook , and destroyed at OnDestroy
*/
private subscription;
ngOnInit(){
this.subscription = this.pausableSource.subscribe(() => {
//doing changes to the template and changing between slides
});
this.pauser.next(false);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
并且它正常工作。 现在要测试这个组件,我在测试主机组件中给它一些数据,并希望检查它的功能如下:
it("should show the second (.slidingImg img) element after testHost.data[0].time seconds
have passed (which here, is 2 seconds)", () => {
//testing
});
我尝试了许多我在文档或互联网上找到的东西,但它们都不适合我。问题在于,我无法用可观察计时器执行下一步行动的方式模仿时间的流逝,而且就像没有时间过去一样。对我来说有两种方式是:
it("should show the second (.slidingImg img) element after testHost.data[0].time seconds
have passed (which here, is 2 seconds)", fakeAsync(() => {
fixture.detectChanges();
tick(2500);
flushMicrotasks();
fixture.detectChanges();
let secondSlidingImg = fixture.debugElement.queryAll(By.css('.slidingImg'))[1].query(By.css('img'));
expect(secondSlidingImg).toBeTruthy();
//error: expected null to be truthy
}));
我从angular2 docs那里得到了这个。
和
beforeEach(() => {
fixture = TestBed.createComponent(TestHostComponent);
testHost = fixture.componentInstance;
scheduler = new TestScheduler((a, b) => expect(a).toEqual(b));
const originalTimer = Observable.interval;
spyOn(Observable, 'interval').and.callFake(function(initialDelay, dueTime) {
return originalTimer.call(this, initialDelay, dueTime, scheduler);
});
// or:
// const originalTimer = Observable.timer;
// spyOn(Observable, 'timer').and.callFake(function(initialDelay, dueTime) {
// return originalTimer.call(this, initialDelay, dueTime, scheduler);
// });
scheduler.maxFrames = 5000;
});
it("should show the second (.slidingImg img) element after testHost.data[0].time seconds
have passed (which here, is 2 seconds)", async(() => {
scheduler.schedule(() => {
fixture.detectChanges();
let secondSlidingImg = fixture.debugElement.queryAll(By.css('.slidingImg'))[1].query(By.css('img'));
expect(secondSlidingImg).toBeTruthy();
//error: expected null to be truthy
}, 2500, null);
scheduler.flush();
}));
我从this question获得了这种方法。
所以我非常需要知道我应该如何在单元测试中模拟时间段,以便组件的可观察时间间隔真正触发......
版本:
angular: "2.4.5"
"rxjs": "5.0.1"
"jasmine": "~2.4.1"
"karma": "^1.3.0"
"typescript": "~2.0.10"
"webpack": "2.2.1"
答案 0 :(得分:0)
fakeAsync
在某些情况下不适用于RxJ。您需要在RxJs中手动移动内部计时器。遵循这些原则:
import {async} from 'rxjs/internal/scheduler/async';
...
describe('faking internal RxJs scheduler', () => {
let currentTime: number;
beforeEach(() => {
currentTime = 0;
spyOn(async, 'now').and.callFake(() => currentTime);
});
it('testing RxJs delayed execution after 1000ms', fakeAsync(() => {
// Do your stuff
fixture.detectChanges();
currentTime = 1000;
tick(1000);
discardPeriodicTasks();
expect(...);
}));
});