You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular单元测试时无法为Mat Table的dataSource赋值测试数据

Angular Material 表格单元测试数据不生效解决方案

你这个问题是写Angular Material表格单元测试的常见坑,按下面步骤排查修改就能跑通:

  • 第一优先级处理ngOnInit里的HTTP请求覆盖测试数据的问题:你现在手动给defaultData赋值再调用filterTable,但ngOnInit里触发的HTTP请求是异步的,等前面同步代码执行完,请求返回会直接把sortedData覆盖成接口返回值,测试环境里接口要么返回空要么报错,自然渲染不出你要的3行数据。
  • 第二要确认测试模块导入了完整的Material依赖:如果TestBed配置里没导入MatTableModule、MatSortModule,Angular根本识别不了mat-table、mat-row这些指令,查出来的节点列表永远是空的。
  • 第三要处理渲染时序问题:MatTable的行渲染不是同步执行的,靠whenStable+done回调很容易漏等异步队列,用fakeAsync工具控制时序比手动写done回调稳得多。

可直接复用的修改示例

首先改测试模块的配置,先把依赖补全、mock掉数据接口:

// 顶部记得引入对应的模块和工具
import { MatTableModule } from '@angular/material/table';
import { MatSortModule } from '@angular/material/sort';
import { fakeAsync, flush, tick } from '@angular/core/testing';
import { of } from 'rxjs';

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [MatTableModule, MatSortModule],
    declarations: [YourBusinessComponent],
    providers: [
      // mock掉组件里用来发HTTP请求的业务服务,避免真实请求干扰测试
      {
        provide: YourDataService,
        useValue: {
          getCustomerList: jasmine.createSpy().and.returnValue(of([]))
        }
      }
    ]
  }).compileComponents();
});

然后改测试用例,不要手动硬塞数据,直接让mock接口返回你的测试数据,模拟真实运行逻辑:

const testCustomers: Customer[] = [
  // 放3条你的测试实体即可
  {id: 1, name: '客户A'},
  {id: 2, name: '客户B'},
  {id: 3, name: '客户C'},
];

it("should correctly render 3 rows of customer data", fakeAsync(() => {
  // 让mock服务直接返回测试数据
  const mockService = TestBed.inject(YourDataService);
  mockService.getCustomerList.and.returnValue(of(testCustomers));

  // 第一次触发变更检测,执行ngOnInit发起请求、赋值数据
  fixture.detectChanges();
  // 清空所有异步队列,等请求返回、filterTable执行、数据赋值全跑完
  flush();

  // 先验证数据本身赋值正确,避免白等渲染
  expect(component.sortedData.length).withContext('sortedData should have 3 items').toBe(3);

  // 触发第二次变更检测,通知表格渲染行
  fixture.detectChanges();
  // 等表格内部的异步渲染逻辑执行完
  tick();

  const tableRows = fixture.nativeElement.querySelectorAll("mat-row");
  expect(tableRows.length).withContext('table should render 3 rows').toEqual(3);
}));

其他常见踩坑点

如果你不想走mock接口的流程,非要手动赋值测试数据,一定要在第一次调用fixture.detectChanges()(也就是触发ngOnInit)之前,先把组件的取数方法重写为空,再提前赋值sortedData,避免被ngOnInit的逻辑覆盖:

it("should render rows with manual data", fakeAsync(() => {
  // 屏蔽ngOnInit里的取数逻辑
  component.fetchCustomerData = () => {};
  // 提前赋值
  component.sortedData = testCustomers;
  fixture.detectChanges();
  flush();
  fixture.detectChanges();
  tick();
  expect(fixture.nativeElement.querySelectorAll("mat-row").length).toBe(3);
}));
  • 如果你是用MatTableDataSource实例作为数据源,不要直接整个替换dataSource对象,要给dataSource.data属性赋值,不然表格订阅不到数据变更,永远不会更新渲染。
  • 如果查不到mat-row,先打印fixture.nativeElement.querySelector('mat-table')看表格节点本身有没有渲染出来,如果表格节点都不存在,要么是模块没导入,要么是模板里的*ngIf控制条件没满足。

内容的提问来源于stack exchange,提问作者Gary Kelly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:03:19