Angular8中如何用Jasmine覆盖抽象类EventEmitter单元测试
问题原因
你写的测试无法覆盖订阅逻辑,核心是三个写法错误:
- 错误给
subscribe方法加了spy,直接替换了EventEmitter原生的订阅逻辑,ngOnInit执行时调用this.search.subscribe()走的是你返回的假值,传入的业务回调根本不会被触发 - 你spy的
onSearch属性完全不存在,组件继承自抽象类的EventEmitter实例名是search,这几行spy代码本身就不生效 - 仅调用
ngOnInit只会完成订阅注册,不会主动执行回调内部逻辑——订阅回调只有在search流主动发出值的时候才会运行,你没有触发流发射的动作,自然走不到回调里的代码。
修正方案
删掉所有对search实例核心方法的spy,保留EventEmitter原生能力,按「先注册订阅、再触发流发值、最后断言结果」的流程写用例即可:
it('should run search subscription logic in ngOnInit', () => { // 1. 调用ngOnInit,完成search的订阅注册 component.ngOnInit(); // 如果你需要验证回调里的业务逻辑,可以在这里提前给对应业务方法打spy // 例:spyOn(component, 'yourBusinessMethod'); // 2. 主动触发search发射值,执行订阅回调 component.search.next('test keyword'); fixture.detectChanges(); // 3. 写对应断言验证逻辑执行结果 // 例:expect(component.yourBusinessMethod).toHaveBeenCalledWith('test keyword'); expect(component).toBeTruthy(); });
注意事项
- 除非你要专门验证
subscribe/next这类方法的调用次数、参数,否则不要随便给Observable/EventEmitter的核心方法打spy,会直接破坏流的原生执行逻辑,导致内部回调无法运行 - 父类(包括抽象类)上用@Output声明的属性,会被子类实例完整继承,TestBed创建组件时会自动完成初始化,不需要额外做模拟、替换
- 要覆盖订阅回调代码,必须同时满足两个条件:
- 订阅动作被执行(也就是对应位置的
subscribe()被调用,完成注册) - 订阅的流主动发出值,触发回调执行
- 订阅动作被执行(也就是对应位置的
内容的提问来源于stack exchange,提问作者Gnik
相关产品推荐
相关产品推荐

