如何修复Angular 7含Promise的ngOnInit测试中data未定义问题
解决Angular 7组件异步ngOnInit测试的undefined错误
问题根源
你的组件ngOnInit通过Promise.all读取Storage数据,再调用dataService.getAllData()(Observable)给this.data赋值,属于异步链式操作。测试时直接同步断言,会导致component.data还未被赋值就读取length,触发Cannot read properties of undefined (reading 'length')错误。
组件核心逻辑示例
ngOnInit() { Promise.all([ this.storage.get('key1'), this.storage.get('key2') ]).then(([val1, val2]) => { this.dataService.getAllData(val1, val2).subscribe(data => { this.data = data; }); }); }
解决方案:等待异步操作完成再断言
Angular测试提供两种常用异步处理方式,任选其一即可:
方式1:使用async + fixture.whenStable()
// 定义符合业务预期的模拟数据 const mockData = [{id:1}, {id:2}]; it('should assign data after ngOnInit completes', async () => { // Mock Storage.get返回已resolve的Promise spyOn(storage, 'get').and.returnValue(Promise.resolve('mock-value')); // Mock DataService.getAllData返回预期Observable spyOn(dataService, 'getAllData').and.returnValue(of(mockData)); component.ngOnInit(); await fixture.whenStable(); // 等待所有异步操作(Promise + Observable)完成 fixture.detectChanges(); // 可选:若视图依赖data,触发变更检测更新视图 // 先验证data存在,再校验length expect(component.data).toEqual(mockData); expect(component.data.length).toBe(mockData.length); });
方式2:使用fakeAsync + tick()
import { fakeAsync, tick } from '@angular/core/testing'; const mockData = [{id:1}, {id:2}]; it('should assign data after ngOnInit completes', fakeAsync(() => { spyOn(storage, 'get').and.returnValue(Promise.resolve('mock-value')); spyOn(dataService, 'getAllData').and.returnValue(of(mockData)); component.ngOnInit(); tick(); // 模拟时间推进,直到所有异步任务执行完毕 fixture.detectChanges(); expect(component.data).toEqual(mockData); expect(component.data.length).toBe(mockData.length); }));
关键注意事项
- 正确Mock依赖:必须确保
storage.get返回已resolve的Promise,dataService.getAllData返回Observable(用of()创建),保证异步链能正常走到赋值逻辑。 - TestBed配置注入Mock实例:
beforeEach(() => { const mockStorage = jasmine.createSpyObj('Storage', ['get']); const mockDataService = jasmine.createSpyObj('DataService', ['getAllData']); TestBed.configureTestingModule({ declarations: [YourComponent], providers: [ { provide: Storage, useValue: mockStorage }, { provide: DataService, useValue: mockDataService } ] }); fixture = TestBed.createComponent(YourComponent); component = fixture.componentInstance; storage = TestBed.inject(Storage); dataService = TestBed.inject(DataService); });
内容的提问来源于stack exchange,提问作者Blen
相关产品推荐
相关产品推荐

