如何为含私有@ViewChild子组件的组件编写单元测试?
如何Mock Angular中私有@ViewChild装饰的子组件
针对无法修改主组件代码、需要测试调用子组件方法的场景,以下几种合规方法可以不用//@ts-ignore就能Mock私有@ViewChild的子组件:
方法1:用TestBed.overrideComponent替换子组件依赖
先定义一个Mock子组件,实现原ChildComponent的public方法和属性(主组件调用的部分):
class MockChildComponent { updateTimeStamp = jasmine.createSpy('updateTimeStamp'); // Jest环境用jest.fn() flag = false; }
在测试配置中,通过overrideComponent告诉Angular将主组件依赖的ChildComponent替换为Mock版本:
beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ParentComponent, MockChildComponent] }) .overrideComponent(ParentComponent, { set: { viewProviders: [ { provide: ChildComponent, useClass: MockChildComponent } ] } }) .compileComponents(); }); it('should call child\'s updateTimeStamp and update flag when update is triggered', () => { const fixture = TestBed.createComponent(ParentComponent); const component = fixture.componentInstance; const mockChild = TestBed.inject(ChildComponent) as MockChildComponent; component.update(); expect(mockChild.updateTimeStamp).toHaveBeenCalled(); expect(mockChild.flag).toBe(true); });
这个方法的核心是利用Angular的依赖注入机制,自动将Mock实例注入到主组件的私有@ViewChild属性中,完全不需要直接访问私有成员。
方法2:通过DebugElement替换子组件实例
如果主组件的@ViewChild是通过模板引用查询的,可以通过DebugElement找到子组件并替换其实例:
it('should trigger child update via parent\'s update method', () => { const fixture = TestBed.createComponent(ParentComponent); const component = fixture.componentInstance; const mockChild = new MockChildComponent(); // 查询子组件对应的DebugElement const childDebugEl = fixture.debugElement.query(By.directive(ChildComponent)); // 替换子组件实例 childDebugEl.componentInstance = mockChild; fixture.detectChanges(); component.update(); expect(mockChild.updateTimeStamp).toHaveBeenCalled(); expect(mockChild.flag).toBe(true); });
这种方式直接修改DOM元素关联的组件实例,主组件调用私有@ViewChild时会访问到Mock对象。
方法3:用spyOnProperty访问私有@ViewChild属性
如果你知道私有@ViewChild的属性名(比如主组件中是private childComponent!: ChildComponent),可以通过spyOnProperty来替换其返回值:
it('should invoke child method when parent update runs', () => { const fixture = TestBed.createComponent(ParentComponent); const component = fixture.componentInstance; const mockChild = new MockChildComponent(); // 监听私有属性的getter,返回Mock实例 spyOnProperty(component, 'childComponent', 'get').and.returnValue(mockChild); component.update(); expect(mockChild.updateTimeStamp).toHaveBeenCalled(); });
这个方法不需要修改组件代码,也不用忽略TypeScript检查,属于合规的私有成员访问方式。
内容的提问来源于stack exchange,提问作者ASHISH KARN
相关产品推荐
相关产品推荐

