Mock Axios请求失败场景下,Angular组件测试未触发错误回调
问题排查与解决:Jasmine测试未触发错误分支
问题场景
封装Axios请求的UserUtils类中,updateUserData方法在请求失败时返回rxjs的throwError;UserComponent调用该方法后,期望成功时触发showSuccessModal,失败时触发showErrorModal。但Jasmine测试Mock该方法返回Promise.reject时,始终执行成功分支,报错Error: Expected spy showErrorModal to have been called。
核心问题分析
- Promise链错误处理失效:
UserUtils的catch块返回了rxjs的Observable(throwError),而非Promise.reject。Promise的catch若返回非Promise类型的值(包括Observable),会被当作成功结果传递给下一个then的成功分支,导致组件永远走成功逻辑。 - 组件错误回调参数错误:组件中错误回调的参数名是
err,但调用showErrorModal时传的是error,就算触发错误分支也会传递undefined。 - 测试异步逻辑未等待:测试用例同步执行,未等待
update方法中的Promise异步操作完成就执行断言,此时回调还未触发。
修复步骤
1. 修正UserUtils的错误返回值
将catch块中的throwError替换为Promise.reject,维持Promise链的错误传递:
// utils.ts 修改后 import axios, { AxiosResponse } from 'axios'; axios.defaults.withCredentials = true; axios.defaults.responseType = 'json'; export class UserUtils { public updateUserData(data) { return axios.post('http://mock.rest.server.com:1234/rest/update/user/', data, { withCredentials: true, responseType: 'json' as 'json' }) .then(resp => resp) .catch(error => { // 用Promise.reject替代throwError,保持Promise错误链 return Promise.reject('error updating user data'); }); } }
2. 修正UserComponent的参数错误
将错误回调中传递的参数从error改为err,与回调参数名一致:
// userComponent.ts 修改后 import { UserUtils } from './utils'; // 修复import放在类内部的语法错误 export class UserComponent { public userUtils: UserUtils = new UserUtils(); // 按钮点击方法 public update(content) { this.userUtils.updateUserData(content) .then((data) => { this.showSuccessModal(); }, (err) => { // 参数名与回调一致,避免传递undefined this.showErrorModal(err); }); } // 补充方法定义(测试依赖) showSuccessModal(): void {} showErrorModal(error: any): void {} }
3. 修正Jasmine测试的异步处理
使用async/await等待Promise异步操作完成后再执行断言:
// userComponent.spec.ts 修改后 import { ComponentFixture, TestBed } from '@angular/core/testing'; import { UserComponent } from '../../../user/userComponent'; import { UserUtils } from '../../../user/utils'; describe('User Comp test', () => { beforeAll(async () => { await TestBed.configureTestingModule({ declarations: [UserComponent] }).compileComponents(); }); describe('User Comp (with beforeEach)', () => { let component: UserComponent; let fixture: ComponentFixture<UserComponent>; beforeEach(async () => { fixture = TestBed.createComponent(UserComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should show error modal', async () => { const errorModalSpy = spyOn(component, 'showErrorModal'); // Mock updateUserData返回失败的Promise spyOn(component.userUtils, 'updateUserData').and.returnValue(Promise.reject('error updating')); // 等待异步操作完成 await component.update({test: 'test'}); // 断言错误方法被调用,且参数正确 expect(errorModalSpy).toHaveBeenCalledWith('error updating'); }); }); });
内容的提问来源于stack exchange,提问作者Oam Psy
相关产品推荐
相关产品推荐

