我如何模拟RxJs 6计时器?

MGD*_*ies 9 jasmine angular rxjs6

我们最近从Angular 5更新到Angular 6,并使用它更新了RxJs 6.作为迁移的一部分,计时器使用率已从以下变化:

Observable.timer()
Run Code Online (Sandbox Code Playgroud)

timer()
Run Code Online (Sandbox Code Playgroud)

在我们的测试中有很多地方我们使用以下模式模拟计时器可观察量.

let timerObserver: Observer<any>;

 beforeEach(() => {
 spyOn(Observable, 'timer').and.returnValue(Observable.create(
    ((observer: Observer<any>) => {
      timerObserver  = observer;
    })
  ));
});

it(`should not have any notifications by default`, () => {
   timerObserver.next('');
   ...
});
Run Code Online (Sandbox Code Playgroud)

有人知道如何迁移这种模式吗?


编辑:我在这里创建了一个简化的问题说明:

https://stackblitz.com/edit/angular-v6-testing-template-nm7add

// Hello.Component
      ngOnInit() {
        const timer$ = timer(30);
        timer$.subscribe(() => {
          this.testMe = 'this has been changed';
        });
      }

// Hello.component.spec
  it('should set testMe after a given timer', fakeAsync(() => {
    tick(50);
    expect(fixture.componentInstance.testMe).toBe('this has been changed');
  }));
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我试图让计时器触发而不等待计时器解决.

car*_*ant 8

在使用时fakeAsync,您可以依靠它的修补setInterval来伪造timerobservable 的实现.

但是,当它返回时,您将需要破坏asyncScheduler实例的now方法Date.now().(严格地说,对于timer可观察对象来说,这不是必需的,因为你已经使用过它,但它对于其他一些可观察对象很重要 - 例如delay运算符返回的可观察量).

如果您使用beforeEachafterEach破坏now方法并配置跟踪假时间的函数,您可以非常轻松地使用东西:

import { fakeAsync, tick as _tick } from '@angular/core/testing';
import { asyncScheduler, of, timer } from 'rxjs';
import { delay } from 'rxjs/operators';

describe('fakeAsync and RxJS', () => {

  let tick: (milliseconds: number) => void;

  beforeEach(() => {
    let fakeNow = 0;
    tick = milliseconds => {
      fakeNow += milliseconds;
      _tick(milliseconds);
    };
    asyncScheduler.now = () => fakeNow;
  });

  it('should support timer with fakeAsync', fakeAsync(() => {
    const source = timer(100);
    let received: number | undefined;
    source.subscribe(value => received = value);
    tick(50);
    expect(received).not.toBeDefined();
    tick(50);
    expect(received).toBe(0);
  }));

  it('should support delay with fakeAsync', fakeAsync(() => {
    const source = of(0).pipe(delay(100));
    let received: number | undefined;
    source.subscribe(value => received = value);
    tick(50);
    expect(received).not.toBeDefined();
    tick(50);
    expect(received).toBe(0);
  }));

  afterEach(() => {
    delete asyncScheduler.now;
  });
});
Run Code Online (Sandbox Code Playgroud)

实际上,因为依赖于fakeAsync模拟基于时间的observable可能很有用,所以我在fakeSchedulers我的rxjs-marbles包中添加了一个函数.参见fake-spec.ts例如用法.

实现与上面的代码段基本相同 - 只是包含在一个函数中.


由于写这个答案,并添加fakeSchedulersrxjs-marbles,我已经写了一篇文章测试用假时间.

  • 谢谢,从概念上讲,这对我来说很难理解,但是您为我提供了很多帮助。对于那些有兴趣补充给定说明并了解计时器如何依赖asyncScheduler的人员,我建议您快速浏览一下源代码:https://github.com/ReactiveX/rxjs/blob/febe2ae4f7b29feeaf6bd4ccbdf623ead5045e24/src/internal/可观察/计时器 (2认同)