如何为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
相关产品推荐
相关产品推荐

