Angular Jasmine单元测试如何覆写组件方法默认行为
Angular单元测试spyOn覆写组件方法异常解决方案
初始报错根因
初始代码抛出的could not find an object to spy upon for myMethodName()报错,核心原因是执行spyOn(component, "myMethodName")时,component变量还未被赋值为组件实例,当前值为undefined,Jasmine无法找到要挂载侦听的目标对象。
调整代码顺序、先创建组件拿到实例再挂载spy的思路正确,但仍存在时序问题导致首个测试用例覆写逻辑不生效。
首个用例覆写失效的原因
出现“第一个用例不触发伪造逻辑、后续用例正常”的现象,核心是两个时序问题:
- 组件构造函数执行时机早于spy挂载:
TestBed.createComponent(XComponent)执行时会直接调用组件类的构造函数,如果myMethodName在构造函数中被调用,此时还未执行spyOn挂载侦听,调用会走原始方法逻辑。 - 首次测试的预编译任务抢占时机:第一个用例运行前,Angular TestBed会完成组件的JIT编译、测试模块初始化等前置工作,部分组件初始化逻辑会在编译阶段就被加入任务队列,这部分入队的任务持有的是未被spy替换的原始方法引用,即使后续spy挂载完成,任务执行时也不会触发伪造逻辑。后续用例运行时组件已经完成编译,不存在这类预入队的任务,spy可以正常生效。
修复方案
将spy挂载时机提前到组件实例化之前,直接侦听组件类原型上的目标方法即可,调整后的beforeEach代码如下:
beforeEach(() => { // 提前在原型上挂载spy,所有后续实例化的组件都会继承被侦听的方法 spyOn(XComponent.prototype, "myMethodName").and.callFake(() => console.log('######')); fixture = TestBed.createComponent(XComponent); component = fixture.componentInstance; fixture.detectChanges(); });
如果目标方法不会在构造函数中调用,仅在ngOnInit等生命周期钩子或后续业务逻辑中调用,也可以保留原有在实例上打spy的写法,只需要在TestBed.configureTestingModule执行完成后提前调用TestBed.compileComponents()完成预编译,避免首次运行的编译任务干扰时序即可。
内容的提问来源于stack exchange,提问作者ebarooni
相关产品推荐
相关产品推荐

