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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 05:45:11