Angular Jasmine测试FileReader提示spy未被调用错误求解
FileReader单元测试报错
Expected spy FileReader to have been called.解决方案 问题根因
- 你在组件类初始化阶段就执行了
reader = new FileReader(),而window.FileReader的spy是在it测试用例中才注册的,此时组件已经完成初始化,reader属性已经是真实的FileReader实例,不会触发你spy的构造函数 - 测试构造的
mockEvt结构不符合业务代码要求:业务代码中调用了files.item(0)获取文件,但你构造的files是普通数组,没有item方法,会导致逻辑提前终止 - Mock的FileReader不会自动触发
onload回调,且你没有对parse方法做监听,无法判断回调是否执行
修复后的测试代码
describe('AppComponent', () => { let mockFile = new File(['testData'], 'filename.csv', { type: 'text/csv' }); // 修复mockEvt的files结构,添加item方法 let mockEvt = { target: { files: Object.assign([mockFile], { item: (index: number) => [mockFile][index] }) } }; // onload是属性不是方法,createSpyObj不用传进去 let mockReader: jasmine.SpyObj<FileReader> = jasmine.createSpyObj('FileReader', ['readAsText']); beforeEach(waitForAsync(() => { // 要在组件实例化之前就spy FileReader构造函数 spyOn(window, 'FileReader').and.returnValue(mockReader); TestBed.configureTestingModule({ declarations: [ AppComponent ], providers: [], imports: [HttpClientTestingModule, BrowserDynamicTestingModule], }).compileComponents(); component = fixture.componentInstance; fixture.detectChanges(); spyOn(component, 'readFileOnChange').and.callThrough(); // 监听parse方法 spyOn(component, 'parse').and.callThrough(); })); it('should call parse on onLoad of FileReader', () => { component.readFileOnChange(mockEvt as any); // 验证构造函数调用 expect(window.FileReader).toHaveBeenCalled(); // 验证readAsText调用 expect(mockReader.readAsText).toHaveBeenCalledWith(mockFile, 'UTF-8'); // 手动触发onload回调 mockReader.onload(new ProgressEvent('load')); // 验证parse被调用 expect(component.parse).toHaveBeenCalled(); }); })
核心修改点说明
- 调整
mockEvt的files结构,添加业务代码依赖的item方法,避免逻辑提前返回 - 将
window.FileReader的spy移到beforeEach中组件实例化之前执行,保证组件初始化时拿到的是Mock的FileReader实例 - 新增对
parse方法的spy监听,用于验证回调逻辑是否执行 - 手动调用Mock实例的
onload方法触发回调,模拟真实FileReader加载完成的行为 - 修正Mock对象的声明,
onload是实例属性不是方法,不需要放到createSpyObj的方法列表中
内容的提问来源于stack exchange,提问作者tiana
相关产品推荐
相关产品推荐

