NgRx Effects单元测试:无Marbles模式下catchError分支测试实现
无Marbles方案的NgRx Effects错误分支测试实现
分支行为本质
你当前Effect的错误分支逻辑可拆解为:
- 当
todosService.getTodos()抛出异常时,catchError操作符会捕获异常,将流替换为EMPTY可观察对象 EMPTY的固有特性是:订阅后不向外发出任何值,直接触发完成回调- 因此该分支的测试核心,不需要断言
EMPTY本身,只要验证流的行为符合上述特征即可
可直接复用的测试代码
你之前卡住的断言环节,完全可以通过原生订阅回调实现,不需要引入Marbles工具:
it('服务请求出错时,Effect不应向下游发出任何action', () => { // 配置Mock action流:仅发出一次getTodos触发动作 actions$ = of(getTodos()); // 配置服务Mock:返回错误可观察对象 todosServiceSpy.getTodos.and.returnValue(throwError(() => new Error('接口异常'))); // 跟踪流的运行状态 let emittedResult: unknown; let isStreamCompleted = false; let isStreamErrored = false; // 订阅Effect流,捕获全量状态 effects.loadTodos$.subscribe({ next: (value) => emittedResult = value, complete: () => isStreamCompleted = true, error: (err) => isStreamErrored = true }); // 断言验证 expect(emittedResult).toBeUndefined(); // 流未发出任何下游值 expect(isStreamCompleted).toBeTrue(); // 流正常完成,未抛出未捕获错误 expect(isStreamErrored).toBeFalse(); expect(todosServiceSpy.getTodos).toHaveBeenCalled(); // 验证服务确实被触发,避免假阳性 });
关键注意事项
- 不要做空订阅测试:直接写
effects.loadTodos$.subscribe()没有任何状态捕获逻辑,根本无法完成断言 - 不需要对
EMPTY本身做硬编码匹配:只要验证“无值发出、无错误抛出、正常完成”的行为,就等价于验证了catchError返回EMPTY的逻辑 - 之前注释掉的服务错误Mock写法是正确的:通过
throwError配置服务返回值,即可稳定触发错误分支 - 额外增加的服务调用断言:可以避免出现“根本没走到服务调用逻辑,却误判为分支测试通过”的测试漏洞
内容的提问来源于stack exchange,提问作者Scott DePouw
相关产品推荐
相关产品推荐

