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

如何为Angular5中打开模态框的HttpInterceptor编写单元测试?

为Angular 5的ErrorInterceptor编写单元测试

首先,咱们得明确这个拦截器的核心行为:当HTTP请求抛出错误时,它会调用NgbModal打开错误弹窗,并根据错误状态设置对应的提示消息。所以单元测试的重点就是验证这些行为是否符合预期——不需要真的渲染模态框,只需要确认服务方法被正确调用,参数和消息都对就行。

第一步:准备测试依赖与配置

首先,你需要在测试文件中引入必要的测试工具和模块:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { ErrorInterceptor } from './error.interceptor';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ErrormodalComponent } from './errormodal.component';

然后,在beforeEach里配置TestBed,模拟NgbModal服务(因为我们不想在测试中真的打开模态框),同时注册拦截器和测试用的HttpClient:

describe('ErrorInterceptor', () => {
  let httpClient: HttpClient;
  let httpTestingController: HttpTestingController;
  let modalService: jasmine.SpyObj<NgbModal>;

  beforeEach(() => {
    // 创建NgbModal的模拟对象,监听它的open方法
    const modalSpy = jasmine.createSpyObj('NgbModal', ['open']);

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        ErrorInterceptor,
        { provide: NgbModal, useValue: modalSpy },
        {
          provide: HTTP_INTERCEPTORS,
          useClass: ErrorInterceptor,
          multi: true
        }
      ]
    });

    // 注入所需实例
    httpClient = TestBed.inject(HttpClient);
    httpTestingController = TestBed.inject(HttpTestingController);
    modalService = TestBed.inject(NgbModal) as jasmine.SpyObj<NgbModal>;
  });

  // 测试用例写在这里
});

第二步:编写具体的测试用例

测试用例1:捕获401错误时,打开模态框并设置正确消息

这个用例要验证:当请求返回401状态码时,拦截器会调用modalService.open,传入正确的组件和配置,并且给模态框实例设置对应的消息。

it('should open error modal and set 401 message when HTTP status is 401', () => {
  // 模拟一个模态框组件实例,用来验证message是否被正确设置
  const mockModalInstance = { message: '' };
  // 让open方法返回包含componentInstance的模拟对象
  modalService.open.and.returnValue({ componentInstance: mockModalInstance });

  // 发起一个测试请求
  httpClient.get('/test').subscribe({
    error: () => {} // 捕获错误,避免测试因未处理错误报错
  });

  // 模拟后端返回401错误
  const req = httpTestingController.expectOne('/test');
  req.error(new ErrorEvent('Network error'), { status: 401 });

  // 验证open方法被调用,参数完全匹配
  expect(modalService.open).toHaveBeenCalledWith(ErrormodalComponent, {
    size: 'sm',
    backdrop: 'static'
  });
  // 验证消息被正确设置(顺便提一句:你原代码里的"logo"应该是"login"的笔误吧?)
  expect(mockModalInstance.message).toBe('User session lost, please login...');
});

测试用例2:非401错误时,是否仍触发模态框(按需添加)

如果你的拦截器逻辑是所有错误都打开模态框,只是不同状态消息不同,可以加这个用例:

it('should open error modal for non-401 errors', () => {
  const mockModalInstance = { message: '' };
  modalService.open.and.returnValue({ componentInstance: mockModalInstance });

  httpClient.get('/test').subscribe({
    error: () => {}
  });

  const req = httpTestingController.expectOne('/test');
  req.error(new ErrorEvent('Server error'), { status: 500 });

  // 确认模态框被调用
  expect(modalService.open).toHaveBeenCalled();
  // 如果你的逻辑里有500对应的默认消息,这里可以继续验证message的值
});

测试用例3:成功的请求不会触发模态框

这个用例确保正常请求不会调用模态框服务:

it('should not open modal when request succeeds', () => {
  httpClient.get('/test').subscribe();

  const req = httpTestingController.expectOne('/test');
  req.flush({ data: 'test data' }); // 返回成功响应

  // 验证open方法从未被调用
  expect(modalService.open).not.toHaveBeenCalled();
});

一些小提醒

  • 你原代码里的catch操作符:在Angular 5中需要确保导入了rxjs/add/operator/catch,否则测试会因找不到操作符报错。
  • 模拟模态框实例时,只需要模拟我们关心的属性(比如message)即可,不需要完整的组件实例,这样测试更轻量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:56:26