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

Angular中使用Jest、Jasmine测试模态确认对话框服务的问题求助

Testing Angular ConfirmationDialogService with Jasmine/Karma

作为测试新手,你遇到的问题其实很常见——我们需要测试服务的行为,而不是仅仅模拟方法返回值。直接spyOn服务的confirm方法虽然能快速模拟返回,但没法验证服务内部是否正确和NgbModal交互。下面是一套完整的测试方案,一步步来:

第一步:配置测试环境

首先,我们需要在测试文件中导入必要的模块,然后用Jasmine创建NgbModal的mock对象,避免真的打开模态框。

import { TestBed } from '@angular/core/testing';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmationDialogService } from './confirmation-dialog.service';
import { ConfirmationDialogComponent } from './confirmation-dialog.component';

describe('ConfirmationDialogService', () => {
  let service: ConfirmationDialogService;
  let modalServiceSpy: jasmine.SpyObj<NgbModal>;
  let mockModalRef: Partial<NgbModalRef>;

  beforeEach(() => {
    // 1. 创建模拟的模态框引用,我们可以控制它的返回结果
    mockModalRef = {
      componentInstance: {}, // 用于模拟组件实例的属性
      result: Promise.resolve(true) // 默认模拟用户点击确认的情况
    };

    // 2. 创建NgbModal的spy对象,只模拟我们需要的`open`方法
    modalServiceSpy = jasmine.createSpyObj('NgbModal', ['open']);
    modalServiceSpy.open.and.returnValue(mockModalRef as NgbModalRef);

    // 3. 配置TestBed,注入服务和mock的NgbModal
    TestBed.configureTestingModule({
      providers: [
        ConfirmationDialogService,
        { provide: NgbModal, useValue: modalServiceSpy }
      ]
    });

    // 4. 获取服务实例和spy对象
    service = TestBed.inject(ConfirmationDialogService);
  });

第二步:基础测试

先验证服务能正常创建:

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

第三步:测试服务的核心逻辑

我们需要验证:

  • 调用confirm时,是否正确打开了ConfirmationDialogComponent
  • 是否正确传递了标题、消息、按钮文本等参数
  • 是否返回了模态框的结果
it('should open dialog with correct component, size and component properties', async () => {
    const testTitle = 'Delete Item?';
    const testMessage = 'Are you sure you want to delete this item?';
    const testOkText = 'Delete';
    const testCancelText = 'Keep';
    const testSize = 'lg';

    // 调用服务的confirm方法
    await service.confirm(testTitle, testMessage, testOkText, testCancelText, testSize);

    // 验证modalService的open方法是否被正确调用
    expect(modalServiceSpy.open).toHaveBeenCalledWith(
      ConfirmationDialogComponent,
      { size: testSize }
    );

    // 验证组件实例的属性是否被正确赋值
    const dialogComponent = mockModalRef.componentInstance;
    expect(dialogComponent.title).toBe(testTitle);
    expect(dialogComponent.message).toBe(testMessage);
    expect(dialogComponent.btnOkText).toBe(testOkText);
    expect(dialogComponent.btnCancelText).toBe(testCancelText);
  });

第四步:测试不同用户操作的返回值

接下来测试用户点击确认和取消时,服务的返回结果是否符合预期:

情况1:用户点击确认

it('should resolve to true when user confirms', async () => {
    const result = await service.confirm('Test Title', 'Test Message');
    expect(result).toBe(true);
  });

情况2:用户点击取消

这里需要注意:你的ConfirmationDialogComponent在用户点击取消时,是调用modalRef.close(false)还是modalRef.dismiss()?

  • 如果是close(false),模态框的result会resolve为false:
it('should resolve to false when user cancels', async () => {
    // 修改mock的result为false
    mockModalRef.result = Promise.resolve(false);
    
    const result = await service.confirm('Test Title', 'Test Message');
    expect(result).toBe(false);
  });
  • 如果是dismiss(),模态框的result会reject,这时候我们需要测试reject的情况:
it('should reject when user cancels via dismiss', async () => {
    mockModalRef.result = Promise.reject('User canceled');
    
    // 使用expectAsync来测试Promise的reject
    await expectAsync(service.confirm('Test Title', 'Test Message'))
      .toBeRejectedWith('User canceled');
  });

为什么不直接spyOn服务的confirm方法?

直接spyOn(ConfirmationDialogService, 'confirm')虽然能快速模拟返回值,但这种测试是“黑盒”的——你没有验证服务内部是否正确和NgbModal交互,比如有没有正确传递参数给模态框组件。而我们上面的测试是“白盒”的,能确保服务的逻辑完全符合预期。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:17:41