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

Angular中关闭mat-dialog后触发的delete方法如何编写单元测试?

报错原因
  • 核心原因是dialogService.dialogRef在你执行spy操作时还未初始化:查看DialogService的代码可知,dialogRef仅在调用openDialog方法后才会被赋值,你在调用组件的delete方法(内部会触发openDialog)之前就尝试spydialogRef的afterClosed方法,此时dialogRef为undefined,因此抛出无法对undefined值执行spy的报错。
  • 次要问题是测试执行顺序完全颠倒:你先执行了dialogService.isClosed()再调用组件的delete方法,和实际业务执行逻辑不符。
  • 遗漏了明确的确认返回模拟:你原代码中afterClosed返回空对象,虽然也能通过if判断,但更规范的是明确返回true模拟用户点击确认按钮的行为。
解决方法

推荐直接mockDialogService的公开方法,不需要依赖其内部的dialogRef属性,测试更稳定,正确测试用例如下:

import { fakeAsync, tick } from '@angular/core/testing';
import { of } from 'rxjs';

it('should call documentService delete when user confirms dialog', fakeAsync(() => {
  // GIVEN
  const dialogService = TestBed.inject(DialogService);
  const documentService = TestBed.inject(DocumentService);
  // 模拟用户点击确认,弹窗关闭后返回true
  jest.spyOn(dialogService, 'isClosed').mockReturnValue(of(true));
  // 模拟documentService的delete方法返回
  const deleteSpy = jest.spyOn(documentService, 'delete').mockReturnValue(of(new HttpResponse({})));
  const testDocument = { id: 123 };

  // WHEN
  comp.delete(testDocument);
  // 执行所有微任务,触发Observable订阅逻辑
  tick();

  // THEN
  // 验证弹窗正常打开
  expect(dialogService.openDialog).toHaveBeenCalledWith('', '', '', '');
  // 验证删除方法被正确调用
  expect(deleteSpy).toHaveBeenCalledWith(123);
}));

如果你需要测试DialogService的内部逻辑,必须要用到dialogRef的话,可以用以下方式mock:

it('should call delete service using confirmDialog', fakeAsync(() => {
  // GIVEN
  const dialogService = TestBed.inject(DialogService);
  const documentService = TestBed.inject(DocumentService);
  // 构造mock的dialogRef
  const mockDialogRef = {
    afterClosed: jest.fn(() => of(true))
  } as unknown as MatDialogRef<ConfirmationDialogComponent>;
  // 劫持openDialog方法,手动给dialogRef赋值
  jest.spyOn(dialogService, 'openDialog').mockImplementation(() => {
    dialogService.dialogRef = mockDialogRef;
  });
  const deleteSpy = jest.spyOn(documentService, 'delete').mockReturnValue(of(new HttpResponse({})));

  // WHEN
  comp.delete({ id: 123 });
  tick();

  // THEN
  expect(mockDialogRef.afterClosed).toHaveBeenCalled();
  expect(deleteSpy).toHaveBeenCalledWith(123);
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 02:48:02