Angular:Spec文件中Mock @ViewChildren获取的QueryList类型子组件属性时的报错及解决方法
如何正确Mock Angular中的QueryList类型
这个问题的核心是你直接创建的模拟对象没有满足QueryList类型的全部接口要求——QueryList不只是包含_results、length这些属性,它还定义了map、filter等一系列方法,TypeScript的类型检查会严格验证这一点,所以你的模拟对象才会报错。
下面给你几种可行的修复方案:
方案1:修改组件代码(推荐,遵循Angular最佳实践)
直接访问QueryList的私有属性_results并不是推荐的做法,因为私有属性可能在Angular版本迭代中发生变化。更好的方式是使用QueryList提供的公开方法toArray()来获取子组件数组:
// parent.component.ts checkProperty() { // 使用公开的toArray()方法代替直接访问私有属性 const childComponents = this.childComponent.toArray(); const isNewRow = childComponents.some(item => item.newRowCreated === true); this.newRowEnabled = isNewRow; }
对应的测试用例可以简化很多,只需要模拟toArray()方法返回测试数据即可:
it('test checkProperty() method', () => { // 创建模拟的QueryList,只需要模拟用到的toArray方法 const mockQueryList = jasmine.createSpyObj('QueryList', ['toArray']); mockQueryList.toArray.and.returnValue([{ newRowCreated: true }]); // 类型断言告诉TypeScript这个模拟对象符合QueryList类型 component.childComponent = mockQueryList as unknown as QueryList<any>; component.checkProperty(); expect(component.newRowEnabled).toBe(true); });
方案2:模拟完整的QueryList类型(不修改组件代码)
如果你暂时不想修改组件代码,需要模拟QueryList的所有必要方法和属性。可以用Jasmine的createSpyObj创建包含所有必填方法的模拟对象,再添加_results属性:
it('test checkProperty() method', () => { // 创建包含QueryList所有必填方法的spy对象 const mockQueryList = jasmine.createSpyObj( 'QueryList', ['map', 'filter', 'find', 'reduce', 'forEach', 'some', 'every', 'toArray', 'first', 'last'] ); // 添加需要的_results属性 mockQueryList._results = [{ newRowCreated: true }]; // 可选:如果用到其他方法,可以添加返回值 mockQueryList.toArray.and.returnValue(mockQueryList._results); component.childComponent = mockQueryList as unknown as QueryList<any>; fixture.detectChanges(); component.checkProperty(); expect(component.newRowEnabled).toBe(true); });
方案3:直接创建QueryList实例(不推荐)
你也可以直接使用Angular提供的QueryList构造函数创建实例,但这种方式依赖QueryList的内部实现,稳定性较差:
import { QueryList } from '@angular/core'; it('test checkProperty() method', () => { const mockChildComponents = [{ newRowCreated: true }]; const queryList = new QueryList<any>(); // 手动重置QueryList的内容(推荐用公开的reset方法) queryList.reset(mockChildComponents); component.childComponent = queryList; component.checkProperty(); expect(component.newRowEnabled).toBe(true); });
内容的提问来源于stack exchange,提问作者knbibin
相关产品推荐
相关产品推荐

