本文介绍了如何模拟RxJs 6计时器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们最近从Angular 5更新到了Angular 6,并使用RxJs 6进行了更新.作为迁移的一部分,计时器的使用方式已从:

We've recently updated from Angular 5 to Angular 6, and with it RxJs 6.As part of the migration, the timer usage has changed from:

Observable.timer()

timer()

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

There are a number of places in our tests where we mock timer observables with the following pattern.

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

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

Does anybody know how to migrate this pattern across?

编辑:我在此处创建了该问题的简化图示:

I've created a simplified illustration of the problem here:

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

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

In this example, I'm trying to get timer to trigger without waiting for the timer to resolve.

推荐答案

在使用fakeAsync时,可以依靠其对setInterval的修补来伪造timer可观察的实现.

As you are using fakeAsync, you can rely upon its patching of setInterval to fake the implementation of the timer observable.

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

However, you will need to clobber the asyncScheduler instance's now method, as it returns Date.now(). (Strictly speaking, this isn't necessary for the timer observable, as you've used it, but it will matter for some other observables - e.g. the observable returned by the delay operator).

如果使用beforeEachafterEach掩盖now方法并配置跟踪假时的功能,则可以使工作变得很容易.

You can get things to work pretty easily if you use beforeEach and afterEach to clobber the now method and to configure a function that keeps track of the fake time:

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 软件包.有关示例用法,请参见 fake-spec.ts


Actually, because relying upon fakeAsync to mock the time-based observable is likely to be useful, I've added a fakeSchedulers function to my rxjs-marbles package. See fake-spec.ts for example usage.

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

The implementation is basically the same as that in the above snippet - just wrapped up in a function.

自编写此答案并将fakeSchedulers添加到rxjs-marbles之后,我写了一篇有关使用假时间进行测试.

Since writing this answer and adding fakeSchedulers to rxjs-marbles, I've written an article about Testing with Fake Time.

这篇关于如何模拟RxJs 6计时器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 23:17