angular - 我如何模拟 RxJs 6 计时器?

标签 angular jasmine rxjs6

我们最近从 Angular 5 更新到 Angular 6,并随之更新到 RxJs 6。 作为迁移的一部分,定时器的使用发生了变化:

Observable.timer()

timer()

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

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('');
   ...
});

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


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

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');
  }));

在这个例子中,我试图在不等待计时器解决的情况下触发计时器。

最佳答案

当您使用 fakeAsync 时,您可以依靠它对 setInterval 的修补来伪造 timer observable 的实现。

但是,您需要破坏 asyncScheduler 实例的 now 方法,因为它返回 Date.now()。 (严格来说,这对于 timer observable 来说不是必需的,因为您已经使用了它,但它对其他一些 observable 很重要 - 例如 delay 返回的 observable > 运营商)。

如果你使用 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;
  });
});

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

实现与上面的代码片段基本相同——只是封装在一个函数中。


自从写下这个答案并将 fakeSchedulers 添加到 rxjs-marbles 后,我写了一篇关于 Testing with Fake Time 的文章.

关于angular - 我如何模拟 RxJs 6 计时器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50759469/

相关文章:

angular - 为什么 rxjs 在涉及运算符时会提示定义为 Type[] 的项?

如果不支持浏览器,Angular 2 如何显示警告页面

javascript - 如何使用 Angular Decorator 减少重复代码?

angular - 如何动态获取子组件而不是使用@ViewChild

angular - 无法使用 azure-sdk-for-js 通过 Angular 访问 Azure Data Lake Gen2 的文件系统

javascript - 在 Jasmine 中每次测试后如何自动恢复所有 sinon.js spy ?

angular - 覆盖我的可观察变量会杀死当前订阅者吗?

jasmine - 如何测试包含去抖动运算符的可观察对象?

angular - 错误 TS6200 : Definitions of the following identifiers conflict with those in another file (@types/jasmine)

Angular 6 : Property 'catch' does not exist on type 'Observable<Response>' ?