Angular服务测试中如何测试方法同步抛出的错误用例
问题场景
Angular服务中存在返回Observable类型的方法,部分校验不通过场景会直接同步抛出错误,示例代码如下:
calculateMyItem(a:number): Observable<state> { if (a<1){ throw new Error('Please input valid number'); } return of({item:'item1',status:'success'}); }
编写单元测试时会发现:错误在方法调用阶段就同步抛出,触发时机早于subscribe订阅操作,订阅的错误回调完全无法捕获该错误。例如下方测试写法根本进不到错误处理逻辑,执行service.calculateMyItem(0)时就会直接抛错:
service.calculateMyItem(0).subscribe({ error: err => console.log('error') })
解决方法
方案1:修正服务实现,符合RxJS规范(推荐)
按照Observable的设计约定,流中所有错误都应该走Observable自身的错误通道,不应该在流外同步抛出,这样调用方可以用统一的逻辑处理同步、异步错误。
把同步throw替换为RxJS的throwError即可,修改后代码:
import { throwError, of } from 'rxjs'; calculateMyItem(a:number): Observable<state> { if (a<1){ // 返回一个会发送错误通知的Observable,而非直接同步抛错 return throwError(() => new Error('Please input valid number')); } return of({item:'item1',status:'success'}); }
修改后常规的订阅错误回调、单元测试写法都能正常工作,测试示例:
it('should throw valid error when input number is less than 1', (done) => { service.calculateMyItem(0).subscribe({ next: () => fail('should not return success response for invalid input'), error: (err) => { expect(err.message).toBe('Please input valid number'); done(); } }) })
方案2:不修改源码的测试写法
如果暂时无法调整服务代码,针对同步抛出的错误,不需要走Observable订阅逻辑,直接按照普通同步函数抛错的方式断言即可:
it('should throw valid error when input number is less than 1', () => { expect(() => service.calculateMyItem(0)).toThrowError('Please input valid number'); })
注意:该写法仅能捕获同步抛出的错误,如果方法后续新增异步错误逻辑,测试会直接失效。长期维护的项目优先选择方案1,统一错误处理逻辑,避免同时维护同步、异步两套错误捕获逻辑。
内容的提问来源于stack exchange,提问作者Mohsen Zahedi
相关产品推荐
相关产品推荐

