Angular独立组件单元测试中Jest Mock未正确生效问题排查
问题
我有一个简单的Ionic/Angular独立组件,已精简无关代码。组件依赖ModalController,点击关闭按钮会调用其dismiss方法。编写Jest测试时模拟了ModalController,但测试断言dismiss被调用失败,调试发现mock未被正确使用,此前同类mock在其他测试中有效,请问遗漏了什么?
组件代码
import { IonicModule, ModalController } from '@ionic/angular'; @Component({ selector: 'my-component', templateUrl: 'my-component.html', styleUrls: ['my-component.scss'], standalone: true, imports: [ IonicModule ] }) export class MyComponent implements OnInit { @Input() inputParam: Organization; public paramOne: string; constructor(private modalCtrl: ModalController) {} ngOnInit(): void { this.paramOne = this.inputParam?.id; } onClickClose(): void { this.modalCtrl.dismiss(); } }
测试代码
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ModalController } from '@ionic/angular'; import { MyComponent } from './my.component'; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; let ionicModalControllerMock = { dismiss: jest.fn() }; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MyComponent, NoopAnimationsModule], providers: [{ provide: ModalController, useValue: ionicModalControllerMock }] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; }); it('should dismiss the modal without data on close click', () => { component.onClickClose(); expect(ionicModalControllerMock.dismiss).toHaveBeenCalledWith(); }); });
解决方案
问题出在独立组件的依赖注入优先级上:你的组件是standalone: true,且已经导入了IonicModule,而IonicModule内部会提供ModalController的真实实例。此时你在TestBed.configureTestingModule的根级providers中配置的mock会被组件自身导入模块提供的服务覆盖,导致mock未生效。
修复方法有两种,任选其一即可:
方法一:用withProviders覆盖组件的依赖
修改TestBed的imports配置,通过独立组件的withProviders方法直接为组件注入mock:
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ MyComponent.withProviders([{ provide: ModalController, useValue: ionicModalControllerMock }]), NoopAnimationsModule ] }).compileComponents(); });
方法二:用overrideComponent替换组件的providers
在TestBed配置中,通过overrideComponent直接修改组件的依赖提供:
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MyComponent, NoopAnimationsModule] }) .overrideComponent(MyComponent, { set: { providers: [{ provide: ModalController, useValue: ionicModalControllerMock }] } }) .compileComponents(); });
原理说明:独立组件的依赖注入优先级顺序为组件自身的providers > 导入模块的providers > TestBed根级providers。因此必须直接在组件层级替换ModalController的提供方,才能确保mock被正确注入。
内容的提问来源于stack exchange,提问作者Milos
相关产品推荐
相关产品推荐

