Karma+Jasmine测试Angular路由navigate异步调用失败问题排查
Angular路由导航异步测试失败解决方案
问题背景
我正在开发一款Angular练习应用,使用Karma和Jasmine进行测试。测试路由navigate功能时,由于该调用位于then()回调中,异步特性导致测试失败,报错信息如下:
Expected spy navigate to have been called with:[ [ '/error' ] ] but it was never called。
业务代码
myFunction(): void { functionWhichReturnsPromise().then(() => { this.router.navigate('/error'); }); }
测试代码
describe('myComponent', () => { let component: myComponent; let fixture: ComponentFixture<myComponent>; let router: Router; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [RouterTestingModule], declarations: [myComponent], providers: [], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); fixture = TestBed.createComponent(myComponent); router = TestBed.inject(Router); component = fixture.componentInstance; spyOn('functionWhichReturnsPromise').and.returnValue(Promise.resolve()); fixture.detectChanges(); }); it('should call navigate', () => { const spyRouter = spyOn(router, 'navigate').and.resolveTo(true); component.myFunction(); expect(spyRouter).toHaveBeenCalledWith(['/error']); }); });
问题分析与解决步骤
1. 核心问题:未等待异步操作完成
测试中调用component.myFunction()后立刻执行断言,此时Promise的then()回调还未触发,navigate自然没有被调用,必须让测试等待异步流程完成。
2. 次要问题:Spy写法错误
原测试中spyOn('functionWhichReturnsPromise')的写法不符合Jasmine规范,spyOn需要指定对象和方法名。如果functionWhichReturnsPromise是组件的方法,要写成spyOn(component, 'functionWhichReturnsPromise');如果是服务或全局函数,需先注入对应实例再创建Spy。
修正后的测试代码(async/await版本)
describe('myComponent', () => { let component: myComponent; let fixture: ComponentFixture<myComponent>; let router: Router; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [RouterTestingModule], declarations: [myComponent], providers: [], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); fixture = TestBed.createComponent(myComponent); router = TestBed.inject(Router); component = fixture.componentInstance; // 修正Spy写法:假设functionWhichReturnsPromise是组件的方法 spyOn(component, 'functionWhichReturnsPromise').and.returnValue(Promise.resolve()); fixture.detectChanges(); }); // 使用async/await等待Promise完成 it('should call navigate', async () => { const spyRouter = spyOn(router, 'navigate').and.resolveTo(true); await component.myFunction(); // 等待异步流程结束 expect(spyRouter).toHaveBeenCalledWith(['/error']); }); });
可选方案(fakeAsync + tick版本)
如果偏好Angular测试的fakeAsync语法,可以用tick()模拟时间流逝,触发Promise回调:
it('should call navigate', fakeAsync(() => { const spyRouter = spyOn(router, 'navigate').and.resolveTo(true); component.myFunction(); tick(); // 推进时间,执行所有待处理的异步回调 expect(spyRouter).toHaveBeenCalledWith(['/error']); }));
内容的提问来源于stack exchange,提问作者anyway07
相关产品推荐
相关产品推荐

