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

MatDialog单元测试提示‘SPEC HAS NO EXPECTATIONS’,需验证openDialog调用

Angular MatDialog 单元测试解决方案

问题原因

你看到的SPEC HAS NO EXPECTATIONS提示,是因为当前测试只调用了openDialog方法,但没有添加任何断言逻辑——单元测试的核心是验证预期行为,没有断言的测试相当于只执行了代码但没验证结果,所以会触发这个提示。

完整测试实现

假设你的组件代码结构是这样的(弹窗组件和主组件在同一文件):

@Component({
  selector: 'app-abc',
  template: `<button (click)="openDialog()">打开弹窗</button>`
})
export class abcComponent {
  constructor(private dialog: MatDialog) {}

  openDialog() {
    this.dialog.open(abcDialogComponent);
  }
}

@Component({
  template: `<div>弹窗内容</div>`
})
export class abcDialogComponent {
  constructor(
    @Inject(MAT_DIALOG_DATA) public data: any,
    public dialogRef: MatDialogRef<abcDialogComponent>
  ) {}
}

1. 配置TestBed并模拟MatDialog

用Mockito创建MatDialog的模拟实例,避免依赖真实弹窗服务:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { mock } from 'ng-mocks';
import { abcComponent, abcDialogComponent } from './abc.component';

describe('abcComponent', () => {
  let component: abcComponent;
  let fixture: ComponentFixture<abcComponent>;
  let dialogMock: jasmine.SpyObj<MatDialog>;

  beforeEach(async () => {
    // 创建MatDialog的模拟对象,自动生成open方法的spy
    dialogMock = mock(MatDialog);

    await TestBed.configureTestingModule({
      declarations: [abcComponent, abcDialogComponent],
      providers: [
        { provide: MatDialog, useValue: dialogMock },
        // 弹窗组件必须的依赖,同样模拟
        { provide: MAT_DIALOG_DATA, useValue: {} },
        { provide: MatDialogRef, useValue: mock(MatDialogRef) }
      ]
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(abcComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

2. 编写带断言的测试用例

测试1:调用openDialog时,MatDialog的open方法被正确触发

it('should call MatDialog.open when openDialog is invoked', () => {
    component.openDialog();
    // 断言:dialog.open被调用,且传入的是目标弹窗组件
    expect(dialogMock.open).toHaveBeenCalledWith(abcDialogComponent);
  });

测试2:点击页面按钮时触发弹窗逻辑

如果要测试真实的用户交互(按钮点击):

it('should open dialog when button is clicked', () => {
    const button = fixture.nativeElement.querySelector('button');
    button.click();
    fixture.detectChanges();

    // 断言弹窗服务的open方法被调用
    expect(dialogMock.open).toHaveBeenCalledWith(abcDialogComponent);
  });
});

关键注意事项

  • 必须加断言:测试的意义在于验证预期结果,没有断言的测试只是空跑代码,这也是你收到提示的核心原因。
  • 模拟所有依赖:用Mockito的mock方法替代真实的MatDialog、MatDialogRef等服务,避免测试依赖外部环境。
  • 处理同文件组件:因为弹窗和主组件在同一文件,测试时需要同时声明两个组件,否则TestBed无法识别弹窗组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:29:55