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

Angular单元测试如何Mock document.defaultView.ready 覆盖Observable返回分支

问题排查

首先你当前的测试存在两个核心问题:

  • 你直接mock了待测试的loadScript方法,替换成了返回of('test')的假实现,完全不会执行原方法的代码,所以肯定无法覆盖对应分支
  • 你mock的getTwitterWidgetData方法在业务代码中不存在,不会生效

正确实现方案

你只需要在测试初始化时,给注入的DOCUMENT对象mock出带twttr.ready方法的defaultView即可,ready方法要主动触发传入的回调,才能走到observer.next和observer.complete的逻辑:

import { DOCUMENT } from '@angular/common';
import { TestBed } from '@angular/core/testing';
import { CourseContentElementEmbedTweetService } from './你的服务文件路径';

describe('CourseContentElementEmbedTweetService', () => {
  let service: CourseContentElementEmbedTweetService;
  // 模拟twttr的ready方法,调用时直接执行传入的回调
  const mockTwttrReady = jest.fn((callback) => {
    callback({ mock: 'twitter widget data' });
  });
  // 构造mock的document对象
  const mockDocument = {
    defaultView: {
      twttr: {
        ready: mockTwttrReady
      }
    }
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        CourseContentElementEmbedTweetService,
        // 替换注入的DOCUMENT为我们的mock对象
        { provide: DOCUMENT, useValue: mockDocument }
      ]
    });
    service = TestBed.inject(CourseContentElementEmbedTweetService);
  });

  describe('loadScript()', () => {
    it('should emit data and complete after twitter ready callback triggers', (done: DoneFn) => {
      // 仅mock startScriptLoad,避免真实插入脚本标签
      jest.spyOn(service as any, 'startScriptLoad').mockImplementation(() => {});
      
      service.loadScript().subscribe({
        next: (res) => {
          // 验证返回值符合预期
          expect(res).toEqual({ mock: 'twitter widget data' });
          // 验证ready方法确实被调用
          expect(mockTwttrReady).toHaveBeenCalled();
        },
        complete: () => {
          // 触发done确认异步逻辑完成
          done();
        }
      });
    });

    // 补充覆盖defaultView为null的分支
    it('should not emit when document defaultView is null', (done: DoneFn) => {
      jest.spyOn(service, 'getDocumentDefaultView').mockReturnValue(null);
      const nextSpy = jest.fn();

      service.loadScript().subscribe({
        next: nextSpy,
        complete: () => {
          expect(nextSpy).not.toHaveBeenCalled();
          done();
        }
      });
    });
  });
});

逻辑说明

当原业务代码执行到this.document.defaultView[this.TWITTER_OBJECT].ready(回调)时,会调用我们预定义的mockTwttrReady方法,这个方法会主动执行传入的回调函数,回调内部的observer.next、observer.complete都会被执行,对应代码分支就会被纳入覆盖率统计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 08:30:03