Angular 错误处理方法handleError的单元测试用例编写咨询
Angular handleError 方法单元测试实现方案
我们基于Angular官方提供的HttpClientTestingModule来模拟HTTP请求,覆盖handleError的两个分支(客户端/网络错误、后端返回错误码),同时验证返回错误信息是否符合预期。
前置配置
首先配置测试床,导入依赖并模拟外部服务:
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { HttpErrorResponse } from '@angular/common/http'; import { YourService } from './your-service.service'; // 替换为你自己的服务类路径 import { ConfigManagerService } from './config-manager.service'; // 替换为ConfigManagerService的实际路径 // 模拟依赖的ConfigManagerService class MockConfigManagerService { statesApiUrl = 'https://test-api.com/states'; } describe('YourService', () => { let service: YourService; let httpTestingController: HttpTestingController; // 劫持console.error避免测试输出冗余日志,同时验证日志输出是否正确 let consoleErrorSpy: jasmine.Spy; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ YourService, { provide: ConfigManagerService, useClass: MockConfigManagerService } ] }); service = TestBed.inject(YourService); httpTestingController = TestBed.inject(HttpTestingController); consoleErrorSpy = spyOn(console, 'error'); }); afterEach(() => { // 验证所有预期的请求都已处理,没有多余请求 httpTestingController.verify(); });
如果你使用Jest作为测试框架,仅需将
consoleErrorSpy的类型jasmine.Spy修改为jest.Spy即可,其余逻辑完全通用。
测试用例1:覆盖后端返回错误码分支
通过模拟后端返回非2xx状态码,触发handleError的服务端错误分支:
it('should handle backend error correctly when calling getStates', (done) => { const testCountryId = 1; const mockStatusCode = 500; const mockErrorBody = 'Database connection failed'; service.getStates(testCountryId).subscribe({ next: () => fail('请求预期会失败,不应进入next回调'), error: (returnedError) => { // 验证返回的用户提示符合预期 expect(returnedError).toBe('Value list currently not available.'); // 验证错误日志输出正确 expect(consoleErrorSpy).toHaveBeenCalledWith(`Backend returned code ${mockStatusCode}, body was: ${mockErrorBody}`); done(); } }); // 匹配发出的请求,返回模拟错误 const req = httpTestingController.expectOne(`${MockConfigManagerService.prototype.statesApiUrl}/${testCountryId}`); req.flush(mockErrorBody, { status: mockStatusCode, statusText: 'Internal Server Error' }); });
测试用例2:覆盖客户端/网络错误分支
通过模拟网络异常,触发handleError的客户端错误分支:
it('should handle client network error correctly when calling getStates', (done) => { const testCountryId = 1; const mockNetworkError = new ErrorEvent('ConnectionError', { message: 'Failed to connect to remote server' }); service.getStates(testCountryId).subscribe({ next: () => fail('请求预期会失败,不应进入next回调'), error: (returnedError) => { expect(returnedError).toBe('Value list currently not available.'); expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', mockNetworkError.message); done(); } }); const req = httpTestingController.expectOne(`${MockConfigManagerService.prototype.statesApiUrl}/${testCountryId}`); // 触发客户端网络错误 req.error(mockNetworkError); }); });
可选:单独测试handleError方法
如果需要直接对handleError做单元测试,不需要走getStates调用链路,可以补充以下用例:
it('handleError should return correct user message for client error', () => { const clientError = new HttpErrorResponse({ error: new ErrorEvent('TestError', { message: 'Client side test error' }) }); service.handleError(clientError).subscribe({ error: (err) => { expect(err).toBe('Value list currently not available.'); expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', 'Client side test error'); } }); }); it('handleError should return correct user message for backend error', () => { const backendError = new HttpErrorResponse({ status: 404, error: 'Resource not found' }); service.handleError(backendError).subscribe({ error: (err) => { expect(err).toBe('Value list currently not available.'); expect(consoleErrorSpy).toHaveBeenCalledWith('Backend returned code 404, body was: Resource not found'); } }); });
以上用例可以100%覆盖handleError的所有代码分支,同时验证日志输出和返回值的正确性。
内容的提问来源于stack exchange,提问作者vamsi
相关产品推荐
相关产品推荐

