我如何模拟 RxJs 6 计时器?
How do I mock RxJs 6 timer?
我们最近从 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
方法,因为它 returns Date.now()
。 (严格来说,这对于 timer
observable 不是必需的,因为您已经使用过它,但它对其他一些 observable 很重要 - 例如 delay
运算符返回的 observable)。
如果你使用 beforeEach
和 afterEach
破坏 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
package. See fake-spec.ts
中添加了一个 fakeSchedulers
函数作为示例用法。
实现与上面的代码片段基本相同——只是封装在一个函数中。
自从写下这个答案并将 fakeSchedulers
添加到 rxjs-marbles
之后,我写了一篇关于 Testing with Fake Time 的文章。
我们最近从 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
方法,因为它 returns Date.now()
。 (严格来说,这对于 timer
observable 不是必需的,因为您已经使用过它,但它对其他一些 observable 很重要 - 例如 delay
运算符返回的 observable)。
如果你使用 beforeEach
和 afterEach
破坏 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
package. See fake-spec.ts
中添加了一个 fakeSchedulers
函数作为示例用法。
实现与上面的代码片段基本相同——只是封装在一个函数中。
自从写下这个答案并将 fakeSchedulers
添加到 rxjs-marbles
之后,我写了一篇关于 Testing with Fake Time 的文章。