unit-testing - Angular 2 : how to test a component which has an observable time interval

标签 unit-testing angular rxjs karma-jasmine observable

我有一个幻灯片放映组件,它有一个幻灯片对象的输入数组,只要它在自身的 slide.time 中定义,就会显示每个幻灯片对象。还有两个按钮,单击它们必须滑动到下一个项目并重置计时器。为了完成这项工作,我正在使用这样的 Observables:

/**
 * 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 文档中得到了这个。

和:

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"    

最佳答案

fakeAsync 不适用于 RxJs 的某些情况。您需要手动移动 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(...);
  }));
});

关于unit-testing - Angular 2 : how to test a component which has an observable time interval,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43674151/

相关文章:

objective-c - 如何 TDD UIGestureRecognizers?

python - 如何在不添加任何代码的情况下在 Python 中对单元测试进行基准测试

ruby-on-rails - 如何获取查询以返回我的模拟对象?

arrays - Angular 2 - 从嵌套数组创建 CSV 文件

angular - 防止 Observable 在服务器关闭时重试

javascript - RxJs Debounce 不发出任何值

unit-testing - 当使用 Moq 模拟类时,如何才能 CallBase 只获取特定方法?

angular - 无法将Angular应用程序作为Docker容器运行。没有这样的文件错误

angular - 找不到模块'@angular/cdk/clipboard

javascript - 在 merge() 中添加条件 pipeline() 操作