You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RXJS TestScheduler未触发Observable,Angular Jasmine单元测试断言失败

问题:TestScheduler测试BehaviorSubject时setter未被调用

我在学习用TestScheduler做RXJS Marble测试,测试BehaviorSubject的getter和setter时遇到错误:
Expected spy setVersatilityRowOptions to have been called with:[ VersatilityHeaderRowOptions({ onlyShowCertifiedOperators: true, showOffTeamOperators: false })] but it was never called.


相关代码

服务函数

setVersatilityRowOptions(versatilityRowOptions: VersatilityHeaderRowOptions): void {
  this._versatilityRowOptions.next(versatilityRowOptions);
}

getVersatilityRowOptions(): Observable<VersatilityHeaderRowOptions> {
  return this.$versatilityRowOptions;
}

待测试组件函数

updateVersatility(): void {
  this.versatilityApiService.getVersatilityRowOptions()
    .subscribe(versatilityRowOptions => {
        this.versatilityApiService.setVersatilityRowOptions(versatilityRowOptions);
  });
}

测试文件(已完成Mock和服务注入)

const testScheduler = new TestScheduler((actual, expected) => {
  expect(actual).toEqual(expected);
});

describe('updateVersatility()', () => {
  it('should update behavior subject', () => {
    testScheduler.run(({cold}) => {
      const source1$ = cold('--(x|)', {x: mockVersatilityHeaderRowOptions});  
    spyOn(component['versatilityApiService'],'getVersatilityRowOptions')
      .and.returnValue(source1$);
    spyOn(component['versatilityApiService'], 'setVersatilityRowOptions');

    component.updateVersatility();

    getTestScheduler().flush();

    fixture.detectChanges();

    expect(component['versatilityApiService'].getVersatilityRowOptions)
      .toHaveBeenCalled();
    expect(component['versatilityApiService'].setVersatilityRowOptions)
      .toHaveBeenCalledWith(mockVersatilityHeaderRowOptions);

});

问题原因及修复方案

核心问题

testScheduler.run()回调内部创建的冷Observable,其调度器是当前TestScheduler实例,但你调用的getTestScheduler().flush()是全局TestScheduler,两者不是同一个实例,导致Observable事件未触发,subscribe回调不执行,setter自然没被调用。另外,testScheduler.run()内部会自动管理时间推进,无需手动调用flush。

修复后的测试代码

const testScheduler = new TestScheduler((actual, expected) => {
  expect(actual).toEqual(expected);
});

describe('updateVersatility()', () => {
  it('should update behavior subject', () => {
    testScheduler.run(({cold}) => {
      const source1$ = cold('--(x|)', {x: mockVersatilityHeaderRowOptions});  
      spyOn(component['versatilityApiService'],'getVersatilityRowOptions')
        .and.returnValue(source1$);
      const setSpy = spyOn(component['versatilityApiService'], 'setVersatilityRowOptions');

      component.updateVersatility();

      fixture.detectChanges();

      expect(component['versatilityApiService'].getVersatilityRowOptions).toHaveBeenCalled();
      expect(setSpy).toHaveBeenCalledWith(mockVersatilityHeaderRowOptions);
    });
  });
});

额外优化点

  • 将setter的spy赋值给变量,让断言代码更简洁
  • 若Angular版本支持,可结合fakeAsync/tick进行Marble测试,确保调度器实例统一

内容的提问来源于stack exchange,提问作者Brock Bergelin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:25:30