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
相关产品推荐
相关产品推荐

