Angular测试问题:如何监视构造函数中调用的Service函数
解决Angular组件构造函数中Service方法调用的测试问题
你说得没错,当前的测试代码确实没法捕获构造函数里的service.start()调用——因为你是先创建了组件实例(这时候构造函数已经执行完了),才去给Service方法加的spy,这时候黄花菜都凉了😅。要解决这个问题,核心就是在组件实例化之前就把Service的spy设置好,下面给你两种常用的解决方案:
方案一:通过TestBed.overrideProvider提前注入Spy对象
这种方法是在配置测试模块的时候,直接提供一个已经设置好spy的Service实例,这样组件构造函数执行时调用的就是这个带spy的方法。代码修改如下:
// 第一个beforeEach,配置测试模块时就准备好spy beforeEach(async(() => { // 创建TestService的spy对象,指定要监视的方法 const testServiceSpy = jasmine.createSpyObj('TestService', ['start']); TestBed.configureTestingModule({ declarations: [AppComponent], // 用spy对象替代真实的TestService providers: [{ provide: TestService, useValue: testServiceSpy }] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AppComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('start gets called', () => { // 从TestBed获取spy对象,断言方法被调用 const testService = TestBed.inject(TestService) as jasmine.SpyObj<TestService>; expect(testService.start).toHaveBeenCalled(); });
这种方式的好处是你可以完全控制Service的行为,比如用and.returnValue()模拟返回值,适合不需要依赖真实Service实现的测试场景。
方案二:在创建组件前先获取Service并设置Spy
如果你需要保留Service的原有实现(比如用and.callThrough()),可以在调用createComponent()之前,先从TestBed中获取Service实例并设置spy:
beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AppComponent], providers: [TestService] // 还是用真实的Service }).compileComponents(); })); beforeEach(() => { // 先获取Service实例,此时还没创建组件 const service = TestBed.inject(TestService); // 给start方法设置spy spyOn(service, 'start').and.callThrough(); // 现在才创建组件,构造函数会调用已被spy的方法 fixture = TestBed.createComponent(AppComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('start gets called', () => { const service = TestBed.inject(TestService); expect(service.start).toHaveBeenCalled(); });
这里的关键是TestBed.inject(TestService)要在createComponent()之前执行,这样组件构造函数执行时,使用的已经是被监视过的Service实例了。
总结一下,两种方法的核心都是把spy的创建时机提前到组件实例化之前,这样才能捕获到构造函数里的方法调用。
内容的提问来源于stack exchange,提问作者Kenny
相关产品推荐
相关产品推荐

