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

如何Mock BsModalRef的onClose.subscribe以覆盖Angular模态框测试代码

解决方案

核心逻辑是构造符合ModalConfirmComponent结构的mock content对象,将onClose替换为可主动触发的Subject,测试时手动发射值即可触发订阅内的逻辑。

步骤1:调整ModalService的mock实现

在测试配置中,提前声明可控制的onClose Subject,修改modalService.show的返回值:

// 测试用例外层声明,用于主动控制模态框返回值
let mockModalOnClose: Subject<boolean | undefined>;

// spyOn替换show方法的返回值
spyOn(mockModalService, 'show').and.callFake(() => {
  mockModalOnClose = new Subject<boolean | undefined>();
  return {
    id: 1,
    content: {
      // 空实现组件方法,避免调用时报错
      showConfirmationModal: jasmine.createSpy('showConfirmationModal'),
      onClose: mockModalOnClose
    },
    hide: jasmine.createSpy('hide'),
    setClass: jasmine.createSpy('setClass'),
    onHide: new EventEmitter(),
    onHidden: new EventEmitter(),
  };
});

步骤2:修改测试用例,主动触发订阅逻辑

分场景测试确认/取消两种分支,示例测试确认添加元素的场景:

describe('addElementWithConfirmation()', () => {
  it('should add element when confirm modal is confirmed', () => {
    spyOn(service, 'canCourseContentElementBeAdded').and.returnValue(true);
    spyOn(service, 'hideAddElementMenu').and.callThrough();
    // 提前获取ADD方法的引用,验证是否被调用
    const addMethodSpy = spyOn(ADD_COURSE_CONTENT_ELEMENT_MAP, CourseContentElementsMap.ADD_COURSE_CONTENT_ELEMENT_AUDIO).and.callThrough();
    
    const newCourseContents: ICourseContent[] = JSON.parse(JSON.stringify(courseContents));
    const testContentUid = newCourseContents[0].uid;
    const testElementUid = `${CourseContentElementType.AUDIO}-${UtilService.generateRandomString(10)}`;

    // 调用目标方法
    service.addElementWithConfirmation(
      course,
      newCourseContents,
      testContentUid,
      testElementUid,
      0,
      true,
      CourseContentElementsMap.ADD_COURSE_CONTENT_ELEMENT_AUDIO,
      'test'
    );

    // 手动触发模态框确认事件,发射true
    mockModalOnClose.next(true);

    // 验证逻辑执行结果
    expect(service.canCourseContentElementBeAdded).toHaveBeenCalled();
    expect(service.hideAddElementMenu).toHaveBeenCalledWith(true);
    expect(addMethodSpy).toHaveBeenCalledWith(newCourseContents, testElementUid, testContentUid);
  });

  // 取消场景用例,发射false即可验证取消分支
  it('should not add element when confirm modal is canceled', () => {
    spyOn(service, 'canCourseContentElementBeAdded').and.returnValue(true);
    spyOn(service, 'hideAddElementMenu').and.callThrough();
    const addMethodSpy = spyOn(ADD_COURSE_CONTENT_ELEMENT_MAP, CourseContentElementsMap.ADD_COURSE_CONTENT_ELEMENT_AUDIO).and.callThrough();
    
    const newCourseContents: ICourseContent[] = JSON.parse(JSON.stringify(courseContents));
    service.addElementWithConfirmation(
      course,
      newCourseContents,
      newCourseContents[0].uid,
      `${CourseContentElementType.AUDIO}-${UtilService.generateRandomString(10)}`,
      0,
      true,
      CourseContentElementsMap.ADD_COURSE_CONTENT_ELEMENT_AUDIO,
      'test'
    );

    // 手动触发模态框取消事件,发射false
    mockModalOnClose.next(false);

    expect(service.hideAddElementMenu).toHaveBeenCalledWith(true);
    // 验证添加方法未被调用
    expect(addMethodSpy).not.toHaveBeenCalled();
  });
});

补充说明

如果用例涉及异步逻辑,可套上fakeAsync+tick或者waitForAsync保证执行时序正确,上述实现默认Subject发射值是同步执行,普通场景足够覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 01:00:03