Jasmine单元测试中组件只读@Output属性无法操作及异步测试优化
问题解决方案
1. 解决@Output只读无法赋值的报错
你遇到的只读报错是因为Angular在编译组件时,会将@Output修饰的EventEmitter实例设置为只读属性,禁止外部直接修改实例引用,所以直接覆盖uploadFinished的赋值操作会抛出异常。你不需要重新构造一个带spy的对象,直接监听原有实例的emit方法即可:
把测试代码里的
component.uploadFinished = {emit: jasmine.createSpy()};
替换为
spyOn(component.uploadFinished, 'emit');
spyOn会自动在原有对象的方法上挂载间谍,既可以监听到调用情况,也不会修改uploadFinished本身的引用,自然不会触发只读报错。
2. 优化异步测试逻辑,去掉setTimeout
你用了Angular官方的HttpTestingController来mock请求,调用req.flush()之后请求的响应就会立即返回,不需要手动加1秒延迟等待。再加上你的fileUpload是async异步方法,你可以直接用Angular测试工具提供的fixture.whenStable()等待所有异步任务执行完成即可:
把原来的setTimeout部分
await (new Promise((resolve, reject) => { setTimeout(()=>{ expect(component.uploadFinished.emit).toHaveBeenCalledWith({response: jasmine.any(HttpResponse)}) return resolve(true); }, 1000); }))
直接替换为:
await fixture.whenStable(); expect(component.uploadFinished.emit).toHaveBeenCalledWith({response: jasmine.any(HttpResponse)});
fixture.whenStable()会等待所有微任务(包括async方法的Promise回调、rxjs异步流转)都执行完成后才resolve,测试执行速度更快,也不会出现因为环境差异导致的超时/等待时间不足的不稳定问题。
可选优化方案:使用fakeAsync
如果你不想用async/await的写法,也可以用Angular提供的fakeAsync和tick来处理异步,测试代码结构更清晰:
it('should emit success response', fakeAsync(() => { spyOn(component.uploadFinished, 'emit'); component.uploadConfig = { method: 'POST', url: '/api/attachments', fieldName: 'file', headers: new HttpHeaders({ 'Accept': 'application/json' }) }; component.handleFiles(createFileList(['matching.fmwr'])); fixture.detectChanges(); component.fileUpload(); // trigger upload // mock request const attachment = { id: 201, fileName: 'matching.fmwr' }; const req = httpMock.expectOne('/api/attachments'); req.flush(attachment); httpMock.verify(); tick(); // 推进所有异步任务执行完成 expect(component.uploadFinished.emit).toHaveBeenCalledWith({response: jasmine.any(HttpResponse)}); }));
内容的提问来源于stack exchange,提问作者Gini
相关产品推荐
相关产品推荐

