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

Angular单元测试中无法Mock BehaviorSubject的问题求助

Angular 16单元测试Mock BehaviorSubject报错:subscribe is not a function

我在Angular 16组件的ngOnInit中订阅了subscribersService的tableList$(一个BehaviorSubject):

ngOnInit() {                                                   
  const { pageNumber } = this.subscribersService.getMiscValues();
  this.subscribersService.initPage(pageNumber);
  this.subscribersService.tableList$.subscribe((tableList) => {
    // this.tableList = this.deleteSubscribersService.setDeleteCheckboxStates(tableList);                    
  });                                                                                
} 

编写单元测试时尝试Mock这个BehaviorSubject,却报错:this.subscribersService.tableList$.subscribe is not a function。我也试过subscribersServiceMock.tableList$.and.returnValue({ subscribe: () => tableListMock$.subscribe });,但问题依旧。

我的测试代码如下:

fdescribe('ManageSubscribersComponent', () => {
  let component: ManageSubscribersComponent;
  let fixture: ComponentFixture<ManageSubscribersComponent>;
  let miscMockValues;
  let tableMockData;
  let tableListMock$;
  let dialogServiceMock
  let dialogSubjectMock;
  let subscribersServiceMock;
  let deleteSubscribersServiceMock;

  const displayedColumns = [
    'id',
    'name',
    'description',
    'createdBy',
    'createdOn',
    'updatedBy',
    'updatedOn',
  ];

  beforeEach(() => {
    tableListMock$ = new Subject();
    dialogSubjectMock = new Subject();

    dialogServiceMock = jasmine.createSpyObj([
      'open',
      'afterClosed',
    ]);

    deleteSubscribersServiceMock = jasmine.createSpyObj([
      'deleteSubscribers',
    ]);


    subscribersServiceMock = jasmine.createSpyObj([
      'resetMiscValues',
      'getMiscValues',
      'initPage',
      'tableList$',
    ]);

    miscMockValues = {
      pageNumber: 1,
      pageSize: 25,
      sort: '',
      active: true,
      testMode: false,
      searchTerms: '',
    };


    subscribersServiceMock.getMiscValues.and.returnValue(miscMockValues);
    subscribersServiceMock.tableList$.and.returnValue(tableListMock$);
    dialogServiceMock.afterClosed.and.returnValue(dialogSubjectMock);

    TestBed.configureTestingModule({
      declarations: [ManageSubscribersComponent],
      imports: [
        HttpClientTestingModule,
        MatFormFieldModule,
        MatIconModule,
        MatSliderModule,
        MatTableModule,
        MatFormFieldModule,
        MatInputModule,
        BrowserAnimationsModule,
        MatPaginatorModule,
        MatDialogModule,
      ],
      schemas: [
        CUSTOM_ELEMENTS_SCHEMA,
        NO_ERRORS_SCHEMA,
      ],
      providers: [
        {
          provide: SubscribersService,
          useValue: subscribersServiceMock,
        },
        {
          provide: DeleteSubscribersService,
          useValue: deleteSubscribersServiceMock,
        },
      ],
    });

    fixture = TestBed.createComponent(ManageSubscribersComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });


  fit('should init', fakeAsync(() => {
    fixture.whenStable().then(() => {
      expect(component.displayedColumns).toEqual(displayedColumns);
      expect(subscribersServiceMock.getMiscValues).toHaveBeenCalled();
    })
  }));
});

问题原因

tableList$是属性(Observable/BehaviorSubject实例),不是方法,但你用jasmine.createSpyObj把它当成方法来创建Spy,导致subscribersServiceMock.tableList$变成了一个Spy函数,而非Observable对象。调用subscribe时自然会报错,因为函数本身没有这个方法。

解决方案

不要在createSpyObj的方法列表中包含tableList$,而是手动给Mock对象添加这个属性,直接赋值为你的tableListMock$(Subject实例本身就具备subscribe方法):

修改测试中的Mock创建部分:

// 创建Spy时只包含方法,去掉tableList$
subscribersServiceMock = jasmine.createSpyObj([
  'resetMiscValues',
  'getMiscValues',
  'initPage',
]);
// 手动添加tableList$属性,赋值为你的Subject实例
subscribersServiceMock.tableList$ = tableListMock$;

// 移除这行错误代码:subscribersServiceMock.tableList$.and.returnValue(tableListMock$);

这样组件中调用this.subscribersService.tableList$.subscribe时,就会正确调用Subject的subscribe方法,不会再报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 03:04:52