如何测试Angular服务中.pipe(catchError(this.handleError('get' + this.apiName, [])))的错误处理逻辑
测试Angular Service中handleError的调用逻辑
要验证catchError里的handleError是否被正确调用,核心是通过模拟Http错误响应,结合Jasmine的spy来跟踪函数调用。我来一步步给你说明怎么做:
1. 核心思路
我们需要:
- 创建一个模拟的
handleError函数,用来跟踪它的调用情况 - 让
AreaService使用这个模拟函数代替真实的错误处理器 - 触发Http错误响应,验证模拟函数是否被正确调用(包括参数是否符合预期)
2. 修改并新增测试用例
测试getAreas的错误处理逻辑
这个测试会验证当Http请求失败时,handleError是否被正确调用:
it('getAreas should invoke handleError with correct params on HTTP failure', (done) => { // 创建一个模拟的handleError函数,返回空数组Observable const mockHandleError = jasmine.createSpy('handleError').and.returnValue(of([])); // 替换HttpErrorHandler的createHandleError方法,让它返回我们的模拟函数 spyOn(hErrorHandler, 'createHandleError').and.returnValue(mockHandleError); // 重新获取service,确保它使用模拟的handleError service = TestBed.get(AreaService); service.getAreas().subscribe(data => { // 验证返回的错误默认值正确 expect(data).toEqual([]); // 验证handleError被调用,参数是'getAreas'和默认空数组 expect(mockHandleError).toHaveBeenCalledWith('getAreas', []); done(); }); // 触发一个500错误的Http响应 const testRequest = httpTestingController.expectOne(apiUrl); testRequest.flush('Server Error', { status: 500, statusText: 'Internal Server Error' }); });
测试getAreasUnidadLocal的错误处理逻辑
同样的思路,针对带参数的方法:
it('getAreasUnidadLocal should invoke handleError with correct params on HTTP failure', (done) => { const testUnidad = 'test-department'; const mockHandleError = jasmine.createSpy('handleError').and.returnValue(of([])); spyOn(hErrorHandler, 'createHandleError').and.returnValue(mockHandleError); service = TestBed.get(AreaService); service.getAreasUnidadLocal(testUnidad).subscribe(data => { expect(data).toEqual([]); // 注意这里的方法名是'getAreas',和service里的定义一致 expect(mockHandleError).toHaveBeenCalledWith('getAreas', []); done(); }); const testRequest = httpTestingController.expectOne(`${apiUrl}/${testUnidad}`); testRequest.flush('Resource Not Found', { status: 404, statusText: 'Not Found' }); });
顺便修正你现有测试的小问题
你原来的getAreasUnidadLocal should return expected data测试有个问题:你先手动设置了缓存,导致不会发起Http请求,httpTestingController.expectOne会报错。建议把这个测试拆成两个独立的用例:
// 测试缓存命中的场景:直接返回缓存数据,不发起请求 it('getAreasUnidadLocal should return cached data when available', (done) => { const unidad = 't'; const expectedData: Area[] = [ { codArea: '001', nombreArea:'area1', unidad:new UnidadLocal() } ]; service.areasUnidad.set(unidad, expectedData); service.getAreasUnidadLocal(unidad).subscribe(data => { expect(data).toEqual(expectedData); // 验证没有Http请求被发起 httpTestingController.expectNone(`${apiUrl}/${unidad}`); done(); }); }); // 测试缓存未命中的场景:发起请求并缓存结果 it('getAreasUnidadLocal should fetch and cache data when not available', (done) => { const unidad = 't'; const expectedData: Area[] = [ { codArea: '001', nombreArea:'area1', unidad:new UnidadLocal() } ]; service.getAreasUnidadLocal(unidad).subscribe(data => { expect(data).toEqual(expectedData); // 验证数据被成功缓存 expect(service.areasUnidad.get(unidad)).toEqual(expectedData); done(); }); const testRequest = httpTestingController.expectOne(`${apiUrl}/${unidad}`); testRequest.flush(expectedData); });
3. 关键说明
- 我们用
jasmine.createSpy创建模拟函数,既能跟踪调用,又能控制返回值,确保subscribe能收到预期的错误默认值。 - 通过
spyOn(hErrorHandler, 'createHandleError')替换错误处理器的创建逻辑,让service使用我们的模拟函数,这样就能准确跟踪调用情况。 - 每个测试用例结束后,
httpTestingController.verify()会确保所有发起的Http请求都被处理,避免遗漏。
内容的提问来源于stack exchange,提问作者Ross
相关产品推荐
相关产品推荐

