Angular Jasmine单元测试:Spy服务未被调用问题求助
Angular Jasmine单元测试:组件级Providers覆盖TestBed模拟服务问题
组件代码
@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], providers: [HomeService] }) export class AppComponent { title = 'testing-angular'; constructor (private service: HomeService ) {} CallHomeService(): void { this.service.DoStuff(); } }
服务代码
@Injectable() export class HomeService { constructor() { } DoStuff(): void { console.log('homeService has been called') } }
初始测试代码(执行失败)
describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; let appComponent: AppComponent; let homeServiceMock: jasmine.SpyObj<HomeService>; beforeEach(() => { homeServiceMock = jasmine.createSpyObj('HomeService', ['DoStuff']); TestBed.configureTestingModule({ declarations: [AppComponent], providers: [{provide: HomeService, useValue: homeServiceMock}] }); fixture = TestBed.createComponent(AppComponent); appComponent = fixture.componentInstance; }); it('should call DoStuff() when CallHomeService() is called', () => { appComponent.CallHomeService(); expect(homeServiceMock.DoStuff).toHaveBeenCalled(); }); });
报错信息
AppComponent should call DoStuff() when CallHomeService() is called FAILED Expected spy HomeService.DoStuff to have been called. at <Jasmine> at UserContext.apply (src/app/app.component.spec.ts:28:37) at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:375:26) at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:39) at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:374:52)
修改后成功的测试代码
import { TestBed, ComponentFixture } from '@angular/core/testing'; import { AppComponent } from './app.component'; import { HomeService } from './service/home.service'; describe('AppComponent', () => { let fixture: ComponentFixture<AppComponent>; let appComponent: AppComponent; let homeService: jasmine.SpyObj<HomeService>; beforeEach(() => { const homeServiceMock = jasmine.createSpyObj('HomeService', ['DoStuff']); TestBed.configureTestingModule({ declarations: [AppComponent], providers: [] }); TestBed.overrideProvider(HomeService, { useValue: homeServiceMock }); fixture = TestBed.createComponent(AppComponent); appComponent = fixture.componentInstance; }); it('should call DoStuff() when CallHomeService() is called', () => { appComponent.CallHomeService(); expect(homeService.DoStuff).toHaveBeenCalled(); }); });
问题原因与解释
Angular依赖注入系统存在明确的优先级层级:组件自身providers数组声明的服务,优先级高于模块级(包括TestBed配置的测试模块)的providers。
当在TestBed.configureTestingModule的providers中提供模拟服务时,该模拟仅注册在测试模块层级。但AppComponent的@Component装饰器中已声明providers: [HomeService],这会在组件的注入器中创建全新的HomeService实例,完全覆盖测试模块提供的模拟对象——测试中调用CallHomeService()时,实际执行的是组件自身创建的真实服务实例,而非定义的spy对象,因此断言失败。
TestBed.overrideProvider()方法的核心作用就是覆盖组件级别的providers配置,它会直接修改组件元数据中的providers,替换为指定的模拟服务,确保组件注入器使用mock实例,测试断言即可正常生效。
内容的提问来源于stack exchange,提问作者ricardo tenorio
相关产品推荐
相关产品推荐

