You need to enable JavaScript to run this app. 使用Jasmine测试Angular中链式window方法的单元测试方案咨询
优惠活动
大模型
产品
解决方案
定价
更多

使用Jasmine测试Angular中链式window方法的单元测试方案咨询

测试实现方案

你只需要提前构造好完整的链式mock对象结构即可,不需要处理复杂的嵌套spy逻辑,具体实现如下:

完整测试代码

describe('Service: gaming-header.service.ts', () => {
  let service: GamingHeaderService;
  let windowSpy: jasmine.SpyObj<Window>;
  let mockClassList: jasmine.SpyObj<DOMTokenList>;
  let mockHeader: { classList: jasmine.SpyObj<DOMTokenList> };

  beforeEach(() => {
    // 1. 先mock classList的两个方法
    mockClassList = jasmine.createSpyObj('DOMTokenList', ['contains', 'add']);
    // 2. 构造mock的header元素
    mockHeader = { classList: mockClassList };
    // 3. 构造完整的window mock对象,补全document.querySelector的实现
    const mockWindow = jasmine.createSpyObj('Window', [], {
      document: jasmine.createSpyObj('Document', ['querySelector'])
    });

    TestBed.configureTestingModule({
      providers: [
        GamingHeaderService,
        { provide: WINDOW, useValue: mockWindow },
      ],
    });

    service = TestBed.inject(GamingHeaderService);
    windowSpy = TestBed.inject(WINDOW) as jasmine.SpyObj<Window>;
    // 指定querySelector匹配'header'时返回我们的mockHeader
    windowSpy.document.querySelector.and.returnValue(mockHeader);
  });

  // 测试用例1:header无games类时会添加
  it('should add games class to header when class not exists', () => {
    // 模拟当前header没有games类
    mockClassList.contains.withArgs('games').and.returnValue(false);

    service.addHeaderClass();

    expect(mockClassList.add).toHaveBeenCalledOnceWith('games');
  });

  // 测试用例2:header已有games类时不重复添加
  it('should not add games class to header when class already exists', () => {
    // 模拟当前header已有games类
    mockClassList.contains.withArgs('games').and.returnValue(true);

    service.addHeaderClass();

    expect(mockClassList.add).not.toHaveBeenCalled();
  });

  // 可选边界用例:不存在header元素时不会报错
  it('should not throw error when header element not exists', () => {
    windowSpy.document.querySelector.withArgs('header').and.returnValue(null);

    expect(() => service.addHeaderClass()).not.toThrow();
  });
});

原理解释

  • Jasmine创建spy对象时,第三个参数可以传入要mock的对象属性,我们通过这个参数逐层补全window.document的mock结构
  • 提前把classList的两个方法做成独立的spy对象,就可以直接监听方法的调用情况,不需要处理链式调用的spy嵌套
  • 所有逻辑都在测试内存中完成,不需要操作真实DOM,测试运行效率更高,也不会受运行环境影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 11:36:04