求助:使用Jest为Angular HttpInterceptor编写单元测试
Angular GlobalErrorIntercepterService 单元测试实现
待测试拦截器代码
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { catchError, Observable, throwError } from 'rxjs'; import { UnauthorizedErrorDialogComponent } from 'src/app/shared/components/unauthorized-error-dialog/unauthorized-error-dialog.component'; import { SvDialogService } from 'sv-shared-library'; @Injectable({ providedIn: 'root' }) export class GlobalErrorIntercepterService implements HttpInterceptor { constructor(private dialog: SvDialogService) {} intercept( req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { return next.handle(req).pipe( catchError((err) => { console.log(err); if (err.status === 401) { this.dialog.open(UnauthorizedErrorDialogComponent); } return throwError(() => new Error(err)); }) ); } }
单元测试实现
基于Angular测试框架结合Jasmine编写测试,核心是Mock依赖服务并验证拦截器行为是否符合预期。
测试依赖与初始化配置
先导入必要模块并完成TestBed配置,Mock弹窗服务与HTTP处理器:
import { TestBed } from '@angular/core/testing'; import { GlobalErrorIntercepterService } from './global-error-intercepter.service'; import { SvDialogService } from 'sv-shared-library'; import { UnauthorizedErrorDialogComponent } from 'src/app/shared/components/unauthorized-error-dialog/unauthorized-error-dialog.component'; import { HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http'; import { throwError } from 'rxjs'; describe('GlobalErrorIntercepterService', () => { let interceptor: GlobalErrorIntercepterService; let dialogService: jasmine.SpyObj<SvDialogService>; let httpHandler: jasmine.SpyObj<HttpHandler>; beforeEach(() => { const dialogSpy = jasmine.createSpyObj('SvDialogService', ['open']); const handlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']); TestBed.configureTestingModule({ providers: [ GlobalErrorIntercepterService, { provide: SvDialogService, useValue: dialogSpy }, { provide: HttpHandler, useValue: handlerSpy } ] }); interceptor = TestBed.inject(GlobalErrorIntercepterService); dialogService = TestBed.inject(SvDialogService) as jasmine.SpyObj<SvDialogService>; httpHandler = TestBed.inject(HttpHandler) as jasmine.SpyObj<HttpHandler>; });
测试用例1:错误状态码为401时,打开指定弹窗
it('should open UnauthorizedErrorDialogComponent when error status is 401', (done) => { const mockReq = new HttpRequest('GET', '/test'); const mockError = new HttpErrorResponse({ status: 401, error: 'Unauthorized' }); httpHandler.handle.and.returnValue(throwError(() => mockError)); interceptor.intercept(mockReq, httpHandler).subscribe({ error: () => { expect(dialogService.open).toHaveBeenCalledWith(UnauthorizedErrorDialogComponent); done(); } }); });
测试用例2:错误状态码非401时,抛出错误且不触发弹窗
it('should throw error and not trigger dialog when error status is not 401', (done) => { const mockReq = new HttpRequest('GET', '/test'); const mockError = new HttpErrorResponse({ status: 404, error: 'Not Found' }); httpHandler.handle.and.returnValue(throwError(() => mockError)); interceptor.intercept(mockReq, httpHandler).subscribe({ error: (err) => { expect(err).toBeInstanceOf(Error); expect(err.message).toBe(mockError); expect(dialogService.open).not.toHaveBeenCalled(); done(); } }); }); });
关键说明
- 用
jasmine.createSpyObj创建Mock对象,方便验证方法调用情况 - 通过
HttpErrorResponse模拟不同状态码的HTTP错误 - 订阅拦截器返回的Observable,在error回调中完成断言校验
- 使用
done回调处理异步测试逻辑,确保断言在异步操作完成后执行
内容的提问来源于stack exchange,提问作者Tirtha
相关产品推荐
相关产品推荐

