Angular+Jest中RxJS catchError与subscribe场景测试问题排查
解决Angular组件中someAction方法的Jest测试问题
问题场景
组件中的someAction方法逻辑如下:
someAction(ids: string[]): void { this.testService .someActionFromService(ids) .pipe( catchError((error) => { this.close(); // 组件方法 return throwError(() => error); }), ) .subscribe(() => { this.close(); // 调用其他组件方法 }); }
对应的Jest测试代码:
describe('someAction(): ', () => { it('des', fakeAsync(() => { fixture.detectChanges(); const testServiceSpy = testService.someActionFromService.mockReturnValue(new Observable()); // 服务已提前正确Mock const closeSpy = jest.spyOn(component, 'close'); component.someAction(['id1']); fixture.detectChanges(); tick(1000); fixture.detectChanges(); expect(testServiceSpy).toHaveBeenCalledWith(['id1']); // 此处断言失败:close未被调用 expect(closeSpy).toHaveBeenCalled(); })); });
测试报错:
expect(jest.fn()).toHaveBeenCalled() Expected number of calls: >= 1 Received number of calls: 0
问题原因
你当前用new Observable() mock服务返回值,这个Observable既不会发出任何数据,也不会完成或抛出错误,导致subscribe的成功回调和catchError的错误回调都不会被触发,自然close方法不会被调用。
解决方案
需要根据测试场景,mock出能触发对应回调的Observable:
1. 测试成功场景(触发subscribe回调)
用of()创建一个会立即发出值并完成的Observable:
testService.someActionFromService.mockReturnValue(of({}));
2. 测试错误场景(触发catchError回调)
用throwError()创建一个会立即抛出错误的Observable:
testService.someActionFromService.mockReturnValue(throwError(() => new Error('test error')));
完整测试示例
describe('someAction(): ', () => { it('should call close on successful service response', fakeAsync(() => { fixture.detectChanges(); // Mock成功响应 testService.someActionFromService.mockReturnValue(of({})); const closeSpy = jest.spyOn(component, 'close'); component.someAction(['id1']); tick(); // 触发Observable的异步操作 fixture.detectChanges(); expect(testService.someActionFromService).toHaveBeenCalledWith(['id1']); expect(closeSpy).toHaveBeenCalledTimes(1); })); it('should call close on service error', fakeAsync(() => { fixture.detectChanges(); // Mock错误响应 testService.someActionFromService.mockReturnValue(throwError(() => new Error('test error'))); const closeSpy = jest.spyOn(component, 'close'); component.someAction(['id1']); tick(); // 触发Observable的异步操作 fixture.detectChanges(); expect(testService.someActionFromService).toHaveBeenCalledWith(['id1']); expect(closeSpy).toHaveBeenCalledTimes(1); })); });
注意:
tick()不需要传1000,因为of和throwError都是同步触发的Observable,用tick()即可完成异步调度。
内容的提问来源于stack exchange,提问作者Aastha B
相关产品推荐
相关产品推荐

