Angular 5组件单元测试:Mock错误响应及TypeError问题解决
解决Angular Jasmine单元测试中onScopesDataLoadFailed的TypeError问题
看起来你遇到的问题主要来自两个地方:测试代码的结构错误和错误响应的模拟时机不对,咱们一步步来修复:
首先,排查测试代码的问题
你现在的测试里嵌套了it块,这在Jasmine里是不允许的——内部的it('should error')根本不会被执行,导致你模拟的错误抛出逻辑完全没生效。当你调用component.ngOnInit()时,实际还是调用了原来的服务方法,返回的错误结构不符合预期,才会出现Cannot read property 'title' of undefined的错误。
修正后的测试代码示例
我们需要把测试逻辑放在同一个it块里,并且先设置好spy,再调用ngOnInit,这样才能确保错误模拟生效:
import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/throw'; // ... 其他导入 it('should handle error properly when loading scopes on ngOnInit', () => { // 1. 准备模拟的错误数据,确保结构匹配组件里的处理逻辑 const mockErrorResponse = { error: { title: 'Mocked title', status: 404 } }; // 2. Spy on scopeService的getScopesByTenantId方法,模拟抛出错误 // 如果服务是私有属性,就用component['scopeService']访问 spyOn(component.scopeService, 'getScopesByTenantId') .and.returnValue(Observable.throw(mockErrorResponse)); // 3. 可以同时spy on alertService的方法,验证是否被正确调用 spyOn(component.alertService, 'stopLoadingMessage'); spyOn(component.alertService, 'showMessage'); // 4. 调用ngOnInit触发流程 component.ngOnInit(); // 5. 添加断言,验证逻辑是否正确执行 expect(component.scopeService.getScopesByTenantId) .toHaveBeenCalledWith(component._searchText, component._onlyActive); expect(component.alertService.stopLoadingMessage).toHaveBeenCalled(); expect(component.alertService.showMessage) .toHaveBeenCalledWith('Mocked title', 404, MessageSeverity.error); expect(component.rows).toEqual([]); expect(component.loadingIndicator).toBeFalse(); });
额外的防御性优化
为了避免生产环境也出现类似的错误,建议给onScopesDataLoadFailed方法添加防御性检查,确保在error.error不存在时也能正常处理:
onScopesDataLoadFailed(error: any) { // 用更安全的方式判断属性是否存在(兼容Angular 5的写法) if (error && error.error && typeof error.error.title !== 'undefined') { this.alertService.stopLoadingMessage(); this.alertService.showMessage(error.error.title, error.error.status, MessageSeverity.error); this.rows = []; this.loadingIndicator = false; } else { // 处理未知错误的情况 this.alertService.stopLoadingMessage(); this.alertService.showMessage('加载范围数据失败', '未知错误', MessageSeverity.error); this.rows = []; this.loadingIndicator = false; } }
注意事项
- 确保已经正确导入
Observable和throw操作符,Angular 5里需要手动导入rxjs/add/observable/throw; - 如果你的服务是通过私有注入的(比如
private scopeService: ScopeService),测试时需要用component['scopeService']来访问这个私有属性; - 分开测试成功和错误场景,不要把多个测试逻辑混在一个
it块里,保持测试用例的单一职责。
内容的提问来源于stack exchange,提问作者Niranjan
相关产品推荐
相关产品推荐

