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

如何使用Jest测试Observable管道抛出的异常

现有Mock写法的核心问题
  • 错误抛出时机完全不对:HttpService.get() 的返回值约定是Observable类型,你当前的mock实现是在调用get()时同步抛出异常,错误发生在get()执行阶段,后续的.pipe()链式调用根本不会执行,你写在pipe里的catchError完全接不到这个错误。rxjs的catchError只能捕获Observable流生命周期内抛出的错误,捕获不到方法同步执行抛出的异常。
  • 模拟逻辑偏离测试目标:你要验证的是「http请求报错时,业务代码的catchError分支会捕获原始错误、包装抛出NotFoundException」,但当前mock直接让get()抛出NotFoundException,相当于跳过了你写的错误处理逻辑,就算测试跑通也证明不了你的catchError代码是有效的。
  • 缺少必要的执行和断言:整个用例只写了mock逻辑,既没有调用待测试的getRandomRecipes方法,也没有对异常做断言,本质上没有完成任何验证。
正确的测试实现

核心思路是模拟真实场景:让HttpService.get()返回一个抛出http请求错误的Observable,触发流内的错误处理逻辑,再断言业务方法最终返回的Promise会抛出NotFoundException。
首先确保导入了rxjs的throwError用于构造错误流,完整测试代码如下:

import { throwError } from 'rxjs';
import { NotFoundException } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
// 其他已有的测试依赖导入

it("throw NotFoundException when there are no recipes", async () => {
  // mock get方法返回抛出http错误的Observable,和真实请求报错行为一致
  jest.spyOn(HttpService.prototype, 'get')
    .mockImplementationOnce(() => throwError(() => new Error('404 not found')));

  // 调用业务方法,断言Promise拒绝的异常类型符合预期
  await expect(service.getRandomRecipes()).rejects.toThrow(NotFoundException);

  // 可选:校验get方法确实被调用,避免其他逻辑抛出同类型异常导致误判
  expect(HttpService.prototype.get).toHaveBeenCalledTimes(1);
});

补充说明

  • 如果你用Nest标准的TestBed创建测试模块,更推荐在模块的provider里注入自定义的HttpService mock,不需要直接spyOn原型,两种写法效果一致。
  • lastValueFrom会在Observable流报错时,直接把流内的错误作为Promise的reject值抛出,所以你在catchError里包装的NotFoundException,会直接被Promise的rejects断言捕获,不需要额外处理。
  • 不要在mock的Observable里抛你要断言的目标异常,一定要模拟原始http错误,才能真正覆盖到你写的catchError分支。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:48:53