Angular测试:如何在TestBed创建SUT组件前为其函数设置Spy
如何在Angular组件初始化前为SUT函数声明式设置Spy
虽然不建议对被测组件(SUT)自身的方法打Spy(这通常意味着测试设计有问题,应该关注组件行为而非内部实现细节),但如果要验证构造函数里立即执行的方法,确实得在组件实例化前准备好Spy。下面是两种可行的实现方式:
方法1:修改组件类的原型
利用JavaScript原型链特性,在TestBed配置阶段直接把组件原型上的目标方法替换成Spy,这样后续创建的所有组件实例都会用这个Spy方法。
示例代码:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; // 提前声明Spy const myMethodSpy = jasmine.createSpy('myMethod'); beforeEach(async () => { // 在配置TestBed前修改组件原型方法 MyComponent.prototype.myMethod = myMethodSpy; await TestBed.configureTestingModule({ declarations: [MyComponent] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; // 构造函数里执行的myMethod已经被Spy捕获 expect(myMethodSpy).toHaveBeenCalled(); }); });
核心就是在组件实例化前修改原型,确保构造函数执行时调用的是Spy方法。
方法2:创建测试用组件子类替换原组件
继承原组件,重写目标方法为Spy,然后在TestBed里用这个子类替换原组件声明,实现声明式Spy绑定。
示例代码:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; // 建测试子类,重写目标方法 class TestMyComponent extends MyComponent { myMethod = jasmine.createSpy('myMethod').and.callFake(() => super.myMethod()); } describe('MyComponent', () => { let component: TestMyComponent; let fixture: ComponentFixture<TestMyComponent>; let myMethodSpy: jasmine.Spy; beforeEach(async () => { await TestBed.configureTestingModule({ // 用测试子类替换原组件 declarations: [TestMyComponent] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(TestMyComponent); component = fixture.componentInstance; myMethodSpy = component.myMethod as jasmine.Spy; // 验证构造函数中的调用 expect(myMethodSpy).toHaveBeenCalled(); }); });
如果需要保留原方法逻辑,可以用and.callFake(() => super.myMethod())委托调用父类方法,同时捕获调用情况。
为什么overrideComponent不行?
TestBed.overrideComponent主要用来修改组件的元数据(比如模板、样式、输入输出等),没法直接覆盖组件类的方法。它的set方法只能改组件装饰器里的配置,访问不到组件类的实例方法或原型方法,所以没法直接设置Spy。
关于ng-mocks的补充
ng-mocks的MockBuilder主要用来Mock组件的依赖,不是改SUT自身。要Mock SUT的方法,同样可以用MockInstance工具修改组件原型,原理和方法1一致,只是封装得更简洁:
import { MockInstance } from 'ng-mocks'; beforeEach(() => { MockInstance(MyComponent, 'myMethod', jasmine.createSpy('myMethod')); });
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

