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

如何使用Angular Jasmine测试void方法 解决v8升v9测试报错

问题根因
  • 测试代码语法错误:你在测试用例中写了component.dataSource[0].state = 'DISABLE',但你的数据源是存在dataSource.data属性下,直接访问dataSource[0]必然返回undefined,所以触发Cannot set properties of undefined (setting 'state')报错
  • Angular 9 初始化逻辑变更:Angular 9 收紧了组件属性初始化的时序校验,如果你使用的是Angular Material的MatTableDataSource,未提前实例化就直接给dataSource.data赋值,就会偶现dataSource本身为undefined的报错,这是迁移后偶现问题的核心原因
  • 依赖未完成Mock:你没有Mock_cutsServices和swal依赖,异步订阅逻辑未受控也会引发时序类报错
  • 业务代码隐含问题:原cutState方法中的三元表达式未赋值回state属性,等于切换逻辑无效;同时存在拼写错误suscribe应为subscribe、tittle应为title
修复方案

步骤1:修复业务代码&组件初始化

先修正业务代码的拼写和逻辑,同时确保组件内的dataSource提前实例化:

// 组件内声明时直接初始化DataSource
dataSource = new MatTableDataSource<any>();

public cutState(i:number) {
  this.loader = true;
  // 把切换后的值赋值回state
  this.dataSource.data[i].state = this.dataSource.data[i].state === 'ENABLE' ? 'DISABLE' : 'ENABLE';
  // 修正拼写错误subscribe
  this._cutsServices.setCuts(this.dataSource.data[i]).subscribe(response => {
    this.loader = false;
    this.loadCut()
    // 修正拼写错误title
    swal.fire({
      title: `!${this.nameRule} update!`,
      icon: 'success',
      showCancelButton:false,
      confirmButtonText:'exit'
    });
  }, error => {
    this.loader = false
    swal.fire({
      title:'Error',
      icon: error,
      showCancelButton:false,
      confirmButtonText: 'Exit'
    });
  });
}

步骤2:编写完整Mock测试用例

使用Jasmine自带的Spy功能Mock所有外部依赖,用fakeAsync控制异步时序:

import { fakeAsync, flush } from '@angular/core/testing';
import { MatTableDataSource } from '@angular/material/table';
import { of, throwError } from 'rxjs';

// Mock cutsServices
const mockCutsService = jasmine.createSpyObj('CutsService', ['setCuts']);
// Mock swal
spyOn(window, 'swal' as any).and.returnValue(Promise.resolve());

const cuts = [{
  name: 'epale_test',
  state: 'DISABLE'
}];

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [CutComponent],
    // 注入Mock服务替代真实服务
    providers: [
      { provide: CutsService, useValue: mockCutsService }
    ]
  }).compileComponents();
}));

beforeEach(()=> {
  fixture = TestBed.createComponent(CutComponent);
  component = fixture.componentInstance;
  // 提前给dataSource赋值,避免undefined
  component.dataSource = new MatTableDataSource(cuts);
  fixture.detectChanges();
})

it('should toggle state and call service correctly when cutState is triggered', fakeAsync(() => {
  // Mock setCuts返回成功的Observable
  mockCutsService.setCuts.and.returnValue(of({}));
  // 修正访问路径,从dataSource.data下取数据
  component.dataSource.data[0].state = 'DISABLE';
  
  component.cutState(0);
  
  // 验证state切换正确
  expect(component.dataSource.data[0].state).toBe('ENABLE');
  // 验证服务被调用
  expect(mockCutsService.setCuts).toHaveBeenCalledWith(component.dataSource.data[0]);
  // 执行异步回调
  flush();
  // 验证loader状态重置
  expect(component.loader).toBeFalse();
  // 验证弹窗被调用
  expect(swal.fire).toHaveBeenCalled();
}));

it('should handle error correctly when setCuts fails', fakeAsync(() => {
  // Mock setCuts返回错误
  mockCutsService.setCuts.and.returnValue(throwError(() => new Error('test error')));
  component.cutState(0);
  
  flush();
  expect(component.loader).toBeFalse();
  expect(swal.fire).toHaveBeenCalledWith(jasmine.objectContaining({ title: 'Error' }));
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:06:07