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

Angular对话框单元测试报错:this.dialogRef.close不是函数求解决方案

解决Angular对话框单元测试中dialogRef.close is not a function错误

我帮你排查了下代码,问题主要出在MatDialogRef的Mock配置错误和测试中未正确跟踪close方法调用这两个地方,下面一步步给你讲怎么修复:

1. 修正MatDialogRef的Provider配置

你在TestBed里配置MatDialogRef的时候犯了个小错误:

{provide: MatDialogRef, useValue: {dialogMock}},

这里你把dialogMock包在了一个额外的对象里,导致组件注入的dialogRef其实是{dialogMock: {close: ...}}这样的结构,自然找不到直接挂载的close方法。直接把dialogMock作为useValue的值就行:

{provide: MatDialogRef, useValue: dialogMock},

2. 正确设置Spy来跟踪close方法调用

你当前的测试直接断言component.dialogRef.close被调用,但没有给这个方法设置Spy监听。需要提前给Mock的close方法创建Spy,这样才能准确跟踪它的调用情况。另外,Angular新版本里更推荐用waitForAsync替代旧的async语法,我也帮你同步调整了。

修改后的完整测试代码

import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
import {CloneDialogComponent} from "./cloneDialog.component";
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";

describe('CloneDialogComponent', () => {
  let component: CloneDialogComponent;
  let fixture: ComponentFixture<CloneDialogComponent>;
  // 直接在mock里创建close方法的spy,方便后续断言
  const dialogMock = { close: jasmine.createSpy('close') };

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [ CloneDialogComponent ],
      imports: [ MatDialogModule, BrowserAnimationsModule ],
      providers: [
        // 移除了不必要的MatDialogTitle依赖,组件里没用到它
        {provide: MatDialogRef, useValue: dialogMock},
        {provide: MAT_DIALOG_DATA, useValue: []}
      ]
    }).compileComponents();
  }));

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

  it('should be created', () => {
    expect(component).toBeTruthy();
  });

  it('should call onNoClick when No button is clicked', waitForAsync(() => {
    spyOn(component, 'onNoClick');
    const button = fixture.debugElement.nativeElement.querySelector('#no');
    button.click();
    fixture.whenStable().then(() => {
      expect(component.onNoClick).toHaveBeenCalled();
    });
  }));

  it('should call onYesClick when Yes button is clicked', waitForAsync(() => {
    spyOn(component, 'onYesClick');
    const button = fixture.debugElement.nativeElement.querySelector('#yes');
    button.click();
    fixture.whenStable().then(() => {
      expect(component.onYesClick).toHaveBeenCalled();
    });
  }));

  it('should close dialog with false after onNoClick', () => {
    component.onNoClick();
    expect(dialogMock.close).toHaveBeenCalledWith(false);
  });

  it('should close dialog with true after onYesClick', () => {
    component.onYesClick();
    expect(dialogMock.close).toHaveBeenCalledWith(true);
  });
});

额外说明

  • 我把async换成了Angular官方推荐的waitForAsync,同时在按钮点击测试里加了fixture.whenStable()来确保异步操作完成后再断言;
  • 直接在dialogMock里用jasmine.createSpy创建了close方法的Spy,不仅能断言是否被调用,还能验证调用时传入的参数是否正确;
  • 移除了不必要的MatDialogTitle Provider,你的组件里并没有注入这个依赖,完全不需要额外提供。

按照上面的修改,你应该就能解决dialogRef.close is not a function的错误,同时正确测试对话框的关闭逻辑了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:38:34