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

如何对Angular Material对话框执行单元测试?新手求助

如何在Angular中对Material对话框执行单元测试

别担心,作为单元测试新手,刚开始搞Angular Material对话框的测试确实容易摸不着头脑,我结合你的代码一步步来教你怎么写正确的测试用例!

首先,测试触发对话框的组件(DialogModalComponent)

我们需要验证当调用openModal()方法时,对话框是否正确打开、传递的数据是否正确,以及关闭后的回调是否正常执行。

步骤1:设置测试环境

在你的dialog-modal.component.spec.ts里,先配置TestBed,导入必要的模块并声明组件:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DialogModalComponent } from './dialog-modal.component';
import { MatDialogModule, MatDialog } from '@angular/material/dialog';
import { DialogUnitTestComponent } from '../dialog-unit-test/dialog-unit-test.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; // 避免动画导致的测试问题
import { of } from 'rxjs';

describe('DialogModalComponent', () => {
  let component: DialogModalComponent;
  let fixture: ComponentFixture<DialogModalComponent>;
  let dialog: MatDialog;
  let dialogOpenSpy: jasmine.Spy; // 用来监听dialog.open方法

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MatDialogModule, NoopAnimationsModule],
      declarations: [DialogModalComponent, DialogUnitTestComponent] // 声明被打开的对话框组件
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(DialogModalComponent);
    component = fixture.componentInstance;
    dialog = TestBed.inject(MatDialog);
    // 监听dialog.open方法,返回一个模拟的dialogRef
    dialogOpenSpy = spyOn(dialog, 'open').and.returnValue({
      afterClosed: () => of(false) // 模拟关闭时返回false,后续可修改
    } as any);
    fixture.detectChanges();
  });

步骤2:测试openModal是否正确调用对话框

it('should open the dialog when openModal is called', () => {
    component.openModal();
    expect(dialogOpenSpy).toHaveBeenCalled();
    // 验证打开的是目标组件
    expect(dialogOpenSpy).toHaveBeenCalledWith(DialogUnitTestComponent, jasmine.any(Object));
  });

步骤3:验证传递的配置和数据是否正确

it('should pass correct dialog config and data', () => {
    component.openModal();
    const dialogConfig = dialogOpenSpy.calls.mostRecent().args[1];
    // 检查配置项
    expect(dialogConfig.disableClose).toBe(true);
    expect(dialogConfig.autoFocus).toBe(true);
    // 检查传递的数据
    expect(dialogConfig.data).toEqual({ id: 1, Name: "Keshav Sahu", title: 'Angular Dialog Test' });
  });

步骤4:测试对话框关闭后的回调逻辑

it('should handle dialog close event correctly', () => {
    // 模拟对话框关闭时返回true
    const mockDialogRef = {
      afterClosed: () => of(true)
    };
    dialogOpenSpy.and.returnValue(mockDialogRef as any);
    // 监听console.log,验证回调是否执行
    const consoleSpy = spyOn(console, 'log');
    
    component.openModal();
    
    expect(consoleSpy).toHaveBeenCalledWith("Dialog was closed");
    expect(consoleSpy).toHaveBeenCalledWith(true);
  });
});

然后,测试对话框组件本身(DialogUnitTestComponent)

我们需要验证这个组件是否正确接收注入的MAT_DIALOG_DATA,以及关闭按钮的逻辑是否正常。

步骤1:设置测试环境

在dialog-unit-test.component.spec.ts里:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DialogUnitTestComponent } from './dialog-unit-test.component';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

describe('DialogUnitTestComponent', () => {
  let component: DialogUnitTestComponent;
  let fixture: ComponentFixture<DialogUnitTestComponent>;
  let dialogRef: MatDialogRef<DialogUnitTestComponent>;
  const mockData = { id: 1, Name: "Keshav Sahu", title: 'Angular Dialog Test' }; // 模拟传入的数据

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MatDialogModule, NoopAnimationsModule],
      declarations: [DialogUnitTestComponent],
      providers: [
        // 提供模拟的MAT_DIALOG_DATA和MatDialogRef
        { provide: MAT_DIALOG_DATA, useValue: mockData },
        { provide: MatDialogRef, useValue: { close: jasmine.createSpy('close') } }
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(DialogUnitTestComponent);
    component = fixture.componentInstance;
    dialogRef = TestBed.inject(MatDialogRef);
    fixture.detectChanges();
  });

步骤2:验证组件是否正确接收数据

it('should receive and display the correct modal title', () => {
    expect(component.modalTitle).toBe(mockData.title);
    // 验证模板中的标题渲染是否正确
    const titleElement = fixture.nativeElement.querySelector('h2');
    expect(titleElement.textContent).toContain(mockData.title);
  });

步骤3:测试关闭按钮的逻辑

it('should close dialog with false when "No" button is clicked', () => {
    const noButton = fixture.nativeElement.querySelector('button:first-child');
    noButton.click();
    expect(dialogRef.close).toHaveBeenCalledWith(false);
  });

  it('should close dialog with true when "Yes" button is clicked', () => {
    const yesButton = fixture.nativeElement.querySelector('button:last-child');
    yesButton.click();
    expect(dialogRef.close).toHaveBeenCalledWith(true);
  });
});

一些测试小提示

  • 一定要导入NoopAnimationsModule,避免Material组件的动画效果干扰测试结果
  • 单元测试只需要验证逻辑正确性,无需真实渲染对话框,用jasmine.Spy模拟方法调用即可
  • 测试模板时,通过fixture.nativeElement获取DOM元素,验证内容或交互是否符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:52:31