Angular单元测试:Mock HTML Document测试print方法
Angular组件print方法单元测试:Mock Document与iframe并验证打印触发
针对你在Angular组件中实现的print方法,下面是具体的单元测试方案,包括Mock HTML Document和iframe,以及验证打印操作是否被正确触发:
核心思路
我们需要模拟document.getElementById("iframe0")返回的iframe元素,同时给该iframe的contentWindow.print()方法创建一个间谍(spy),这样就能追踪这个打印方法是否被调用。
情况1:组件直接使用全局document
如果你的组件直接调用全局document(就像你现在的代码),可以通过Spy全局document.getElementById来返回模拟的iframe:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; let mockPrintSpy: jasmine.Spy; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [MyComponent] }).compileComponents(); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; // 1. 创建模拟的print方法间谍 mockPrintSpy = jasmine.createSpy('print'); // 2. 创建模拟的iframe对象,包含带spy的contentWindow.print const mockIframe = { contentWindow: { print: mockPrintSpy } }; // 3. Mock全局document.getElementById,让它返回模拟的iframe spyOn(document, 'getElementById').and.returnValue(mockIframe as HTMLElement); }); it('should call iframe contentWindow.print() when print() is invoked', () => { // 调用组件的print方法(参数i可随意传入,你的方法中未使用该参数) component.print(1); // 验证document.getElementById是否传入了正确的iframe ID expect(document.getElementById).toHaveBeenCalledWith('iframe0'); // 验证打印方法是否被触发 expect(mockPrintSpy).toHaveBeenCalled(); }); });
情况2:组件依赖注入DOCUMENT(更规范的做法)
推荐将document通过Angular的依赖注入机制引入组件,这样更利于测试和维护:
调整组件代码:
import { Component, Inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-my', templateUrl: './my.component.html' }) export class MyComponent { constructor(@Inject(DOCUMENT) private document: Document) {} print(i: number) { (this.document.getElementById("iframe0") as any).contentWindow.print(); } }
对应的单元测试:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; import { DOCUMENT } from '@angular/common'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; let mockPrintSpy: jasmine.Spy; let mockDocument: any; beforeEach(async () => { // 提前创建模拟的print间谍和document对象 mockPrintSpy = jasmine.createSpy('print'); mockDocument = { getElementById: jasmine.createSpy('getElementById').and.returnValue({ contentWindow: { print: mockPrintSpy } }) }; await TestBed.configureTestingModule({ declarations: [MyComponent], providers: [ { provide: DOCUMENT, useValue: mockDocument } ] }).compileComponents(); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; }); it('should trigger iframe print via injected document', () => { component.print(0); expect(mockDocument.getElementById).toHaveBeenCalledWith('iframe0'); expect(mockPrintSpy).toHaveBeenCalled(); }); });
关键说明
- 我们用
jasmine.createSpy创建了print方法的间谍,目的是追踪该方法是否被调用,无需实际触发浏览器的打印弹窗。 - 通过Mock
getElementById,让组件代码获取到我们预设的iframe模拟对象,从而将测试与真实DOM环境解耦。 - 测试用例中需要验证两个点:一是
getElementById是否传入了正确的ID("iframe0"),二是print方法是否被执行。
内容的提问来源于stack exchange,提问作者Edson Barbosa Junior
相关产品推荐
相关产品推荐

