Angular 异步输入管道与HttpClient模拟服务的单元测试实现问题
修正后的单元测试实现
你的测试代码核心问题是混用了fakeAsync和Promise.then语法,导致大部分断言逻辑没有实际执行,同时也存在变更检测时机、选择器适配错误的问题,以下是完整可运行的实现:
前置准备(先定义测试用模拟数据)
// 提前定义模拟返回数据 const testBandsRes = { bands: [ { id: 1, name: 'The Beatles' }, { id: 2, name: 'The Rolling Stones' } ] };
测试用例实现
it('should search for bands starting with "The" and validate all flows', fakeAsync(async () => { // 1. 获取输入框元素并输入"The" const inputHarness = await loader.getHarness(MatInputHarness); await inputHarness.setValue('The'); fixture.detectChanges(); // 2. 校验加载指示器正常展示 const loadingSpinner = fixture.debugElement.query(By.css('mat-spinner')); expect(loadingSpinner).toBeTruthy(); expect(component.loading).toBeTrue(); // 3. 等待debounceTime 300ms触发服务调用,beforeEach中已经完成服务mock,无需重复定义 tick(300); // 等待mock服务的异步返回完成 tick(); fixture.detectChanges(); // 4. 校验加载指示器正常隐藏 expect(component.loading).toBeFalse(); expect(fixture.debugElement.query(By.css('mat-spinner'))).toBeFalsy(); // 5. 校验返回的选项正常展示 const autocomplete = await loader.getHarness(MatAutocompleteHarness); const options = await autocomplete.getOptions(); expect(options.length).toBe(2); expect(await options[0].getText()).toBe('The Beatles'); expect(await options[1].getText()).toBe('The Rolling Stones'); // 6. 可选:选中选项校验formControl取值 await options[0].click(); fixture.detectChanges(); expect(component.formControl.value).toEqual(testBandsRes.bands[0]); // 清理剩余异步任务避免报错 discardPeriodicTasks(); }));
关键修改说明
- 用
async/await配合fakeAsync处理Material Harness的异步方法,避免回调丢失 - 严格按照流的执行顺序调用
tick(),分别处理debounceTime等待和服务异步返回 - 每次异步操作完成后调用
fixture.detectChanges()同步UI状态 - 使用官方的
MatAutocompleteHarness获取选项,避免选择器适配不同版本Material的问题
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

