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

