Angular 使用 interval() 进行测试

Angular testing with interval()

在我的 ngOnInit 中,我检查了一条路线,做了一些事情,然后设置了一个 interval

ngOnInit(): void {
    this.routeSubscription = this.route.paramMap.subscribe(x => {
         ...
         // Reload the data every 60 seconds
         interval(60_000)
             .pipe(takeUntil(this.cancelInterval$))
             .subscribe(() => this.rows$ = this.orderService.active())
    })
}

当我尝试进行单元测试时,jasmine 中止,因为异步方法 return 不够快。我正在这样做(作为主要部分的子描述,它执行所有正常的 TestBed 设置):

describe('when showing active orders', () => {
    beforeEach(() => {
        activatedRoute.setParamMap({})
        fixture.detectChanges()
    })

    it('...', async () => {
        await fixture.whenStable()
        ...
    })

好像是因为间隔卡住了。我以为我可以在 beforeEach 方法的末尾调用 discardPeriodicTasks(),但这不起作用。

所以我正在寻找在测试中处理此问题的正确方法,或者在生产代码中寻找一种方法,如果它不是 运行 通过测试,则只进行间隔调用。

Angular CLI:9.0.7
节点:14.4.0
Angular: 9.1.6

与其直接调用 RXJS interval(),不如像这样创建一个简单的中间服务:

import { Injectable } from '@angular/core';
import { interval } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class TimerService {

  interval(ms: number) {
      return interval(ms);
  }

}

在您的组件中注入并使用它:timer.interval(60_000)

现在在您的 unit-tests 中模拟 interval() 的必要行为是微不足道的,例如:

providers: [{ provide: TimerService, useValue: { interval: () => of(1) } }],

您可以使用 fakeAsync 和 tick 来模拟异步行为

it('...', fakeAsync () => { tick(60000); doTestStuff(); })