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

使用Jasmine Marbles测试RxJS catch操作符始终失败

排查Jasmine-Marbles测试失败的原因

我来帮你搞定这个测试失败的问题,其实根源在于对RxJS流行为和jasmine-marbles的marble语法理解有一点小偏差。

问题分析

先看测试失败的输出:

Expected [ Object({ frame: 10, notification: Notification({ kind: 'N', value: 0, error: undefined, hasValue: true }) }), Object({ frame: 10, notification: Notification({ kind: 'C', value: undefined, error: undefined, hasValue: false }) }) ] to equal [ Object({ frame: 10, notification: Notification({ kind: 'N', value: 0, error: undefined, hasValue: true }) }) ].

这段输出的意思很明确:

  • 实际的Observable流在第10帧发出了值0,紧接着发出了完成通知(C)
  • 但你定义的预期流cold('-c', {c: 0})只包含了发出值0的通知,没有完成通知

两者的行为不匹配,所以测试失败了。

为什么实际流会有完成通知?
当error=true时,do操作符在第一个值到来时抛出错误,catch操作符会捕获这个错误并返回Observable.of(0)。而RxJS里的Observable.of(0)的行为是:发出值0之后,立即发出完成信号,所以整个被测试的流会在发出0后直接结束。

解决方案

修改第二个测试用例的预期marble字符串,加上代表流完成的|符号:

it('should handle error', () => {
  const e1 = cold('-a-|', {a: 1});
  const e2 = cold('--b-|', {b: 2});
  // 这里加上|表示流完成
  const expected = cold('-c|', {c: 0});
  const obs: Observable<number> = service(e1, e2, true);
  expect(obs).toBeObservable(expected);
});

修改后,预期流的行为就和实际流完全一致了:在第10帧发出值0,紧接着发出完成通知,测试就能通过。

补充说明

jasmine-marbles的marble语法里:

  • - 代表时间帧
  • 字母(比如c)代表发出的值
  • | 代表流正常完成
  • # 代表流抛出错误

如果你的预期流没有写|,jasmine-marbles会认为这个流是永远不会结束的,但实际流因为of(0)的特性会立即结束,这就是测试失败的核心原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:50:41