Angular 13 Jasmine单元测试debugElement.query返回null排查
问题原因
- 表格行不满足渲染条件:模板里
tbody的*ngIf判断写的是table.data?.length! > 1,只有数据源长度大于1才会渲染数据行,行本身又是*ngFor遍历table.data生成的。测试初始化组件后没有给绑定到表格的stores属性赋值,默认是空数组,直接渲染了noMatches空状态模板,当然查不到目标元素。 - 监控对象完全配错:模板里绑定的
onClickItem是组件自身的方法,不是StoreService里的方法,原测试不仅给服务打桩监控错了对象,连方法名都拼错了(onCLickItem大写了C),就算点到元素也不可能通过断言。 - 赋值后没触发变更检测:就算给组件传了测试数据,不调用
fixture.detectChanges(),Angular不会把数据更新到DOM上,还是查不到元素。
修复方案
- 先构造符合长度要求的测试数据,赋值给组件的
stores属性,注意要满足length > 1的判断条件(如果这个判断本身是业务bug,改成>=1的话测试数据1条就够)。 - 把打桩对象改成组件实例本身的
onClickItem方法,不要错误监控服务方法。 - 赋值后手动调用
fixture.detectChanges()触发视图更新,再去查询DOM元素。
修正后的测试用例代码:
fit('calls onClickItem function when store name is clicked', () => { // 构造2条测试数据,满足*ngIf的渲染条件 const mockStores = [ { fkey: 101, name: 'Giant Food', address: '123 Main St', region: 'North', lastVisit: new Date(), products: 3 }, { fkey: 102, name: 'Walmart', address: '456 Oak Ave', region: 'South', lastVisit: new Date(), products: 1 } ]; component.stores = mockStores; // 监控组件自身的点击方法 spyOn(component, 'onClickItem').and.callThrough(); // 触发变更检测,渲染数据到DOM fixture.detectChanges(); const clickedRow = debugElement.query(By.css('[data-testid="store"]')); // 先断言元素存在,避免后续空指针 expect(clickedRow).withContext('store row should render').toBeTruthy(); // 触发点击事件,不需要额外构造clickEvent,传null即可 clickedRow.triggerEventHandler('click', null); // 断言方法被调用,且传入了正确的fkey参数 expect(component.onClickItem).toHaveBeenCalledOnceWith(101); });
额外优化建议
- 原测试的TestBed配置里没有声明模板中用到的
AppButtonPrimary组件、mdbFormControl、mdbInput等依赖,运行其他用例时会报模板解析错误,可以在TestBed的schemas里加NO_ERRORS_SCHEMA忽略无关组件依赖,或者导入对应MDB模块、声明桩组件。 - 模板里的
*ngIf="table.data?.length! > 1"逻辑不合理,当门店数正好为1时会错误显示无匹配结果,建议同步修正为table.data?.length >= 1。
内容的提问来源于stack exchange,提问作者Luiz Federico
相关产品推荐
相关产品推荐

