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

如何在Jasmine中对throw new Error()代码段编写单元测试

问题根源

你遇到的两个问题本质都是对RxJS异步逻辑的测试写法不正确,还有部分语法错误:

  • 外层try/catch无法捕获异步错误:subscribe的错误回调是异步执行的,调用component.addNew(4)时只是完成了订阅动作,错误回调还未触发,try块就已经执行完毕,catch分支永远不会进入,内部的expect断言从未执行,所以无论填什么内容测试都会显示通过。
  • 未处理的异步错误直接输出控制台:异步抛出的Error不在当前同步执行的上下文里,没有被你的测试代码捕获,Jasmine就会把这个未处理错误直接打印到控制台。
  • 额外的语法错误:你原来的测试中catch分支用到的item变量未声明,就算catch能触发也会先报变量未定义的错误,同时expect的断言对象也写错了:orderMockService.add本身不会抛出错误,抛出错误的是组件内的错误回调逻辑。
修复方案

提供两种常用的修复写法,你可以根据自己的场景选择:

写法1:用done回调捕获全局异步错误

适合不需要修改组件代码的场景,直接重写全局错误拦截逻辑捕获抛出的错误:

import { throwError } from 'rxjs';

// 其余测试初始化逻辑保持不变,比如组件声明、mock service注入等
it('should throw custom error when service add fails', (done) => {
  const testItem = 4;
  const expectedErrorMsg = `Item no ${testItem} was not added to the DB`;
  //  mock service返回错误
  orderMockService.add.and.returnValue(throwError(() => ({ status: 500 })));

  // 重写全局错误拦截,捕获异步抛出的错误
  spyOn(window, 'onerror').and.callFake((errorMsg) => {
    // 断言错误消息符合预期
    expect(errorMsg.toString()).toContain(expectedErrorMsg);
    // 断言service方法被正确调用
    expect(orderMockService.add).toHaveBeenCalledOnceWith(testItem);
    // 通知Jasmine异步测试执行结束
    done();
    // 阻止错误继续输出到控制台
    return true;
  });

  component.addNew(testItem);
});

写法2:用Angular测试工具fakeAsync+tick

更贴合Angular单测的常用写法,不需要修改全局事件:

import { throwError } from 'rxjs';
import { fakeAsync, tick } from '@angular/core/testing';

it('should throw custom error when service add fails', fakeAsync(() => {
  const testItem = 4;
  const expectedErrorMsg = `Item no ${testItem} was not added to the DB`;
  orderMockService.add.and.returnValue(throwError(() => ({ status: 500 })));

  let caughtError: Error | null = null;
  // 拦截控制台错误捕获抛出的异常
  spyOn(console, 'error').and.callFake((err) => {
    if (err instanceof Error) caughtError = err;
  });

  component.addNew(testItem);
  tick(); // 手动触发所有异步任务执行完毕

  expect(orderMockService.add).toHaveBeenCalledOnceWith(testItem);
  expect(caughtError?.message).toBe(expectedErrorMsg);
}));

可选优化(推荐)

如果允许调整组件代码,建议把错误处理逻辑抽成独立方法,测试会更简单,也不需要处理异步捕获的问题:

调整后的组件代码

addNew(item: number) {
  this.service.add(item).subscribe(
    res => {
      this.sendNoti(item);
    },
    err => {
      this.handleAddItemError(item);
    }
  )
}

// 抽离独立的错误处理方法
handleAddItemError(item: number) {
  throw new Error(`Item no ${item} was not added to the DB`);
}

对应的测试代码

import { throwError } from 'rxjs';
import { fakeAsync, tick } from '@angular/core/testing';

it('should trigger error handler when service add fails', fakeAsync(() => {
  const testItem = 4;
  // 监听错误处理方法的调用
  spyOn(component, 'handleAddItemError');
  orderMockService.add.and.returnValue(throwError(() => ({ status: 500 })));

  component.addNew(testItem);
  tick();

  // 直接断言方法被正确调用即可,不需要捕获异步错误
  expect(component.handleAddItemError).toHaveBeenCalledOnceWith(testItem);
}));

// 单独测试错误处理方法的抛出逻辑,同步测试非常简单
it('handleAddItemError should throw correct error message', () => {
  expect(() => component.handleAddItemError(4)).toThrowError('Item no 4 was not added to the DB');
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:24:03