我有一个很大的 .spec 文件,用作(我们称之为)MainComponent 的集成测试。声明包含多个子组件及其子组件。我关心两个使用 EventEmitter 进行通信的组件。当用户单击 ChildComponent 中的按钮时,事件将被发出并触发 ParentComponent 中的函数。
我试图模拟 ParentComponent 但当测试执行时,它会沿着 ParentComponent 的默认路径走。
我无法显示整个文件,但这就是规范的作用:
describe('main component Spec', () => {
let fixture: ComponentFixture<MainComponent>;
let mainComponent: MainComponent;
const parentComponentSpyObj = jasmine.createSpyObj('ParentComponent', ['onEventReceived']);
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [
ParentComponent,
ChildComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [FlexLayoutModule],
providers: [
{ provide: ParentComponent, useValue: parentComponentSpyObj },
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MainComponent);
mainComponent = fixture.componentInstance;
fixture.detectChanges();
});
it(`Should call onEventReceived of ParentComponent when child button is pressed`, () => {
// Given
const childComponentButton = fixture.debugElement.nativeElement.querySelector('#button');
// When
childComponentButton.click();
fixture.detectChanges();
// Then
expect(parentComponentSpyObj.onEventReceived).toHaveBeenCalledTimes(1);
});
});
测试失败,并显示消息 - Expected ParentComponentSpyObj.onEventReceived to have been called once。被调用了 0 次。
问题在于提供的模拟对象未正确注入到组件层次结构中。您需要以替换实际对象的方式提供模拟对象
ParentComponent
。
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
// Import the components and any other required modules
describe('main component Spec', () => {
let fixture: ComponentFixture<MainComponent>;
let mainComponent: MainComponent;
// Create a spy object for ParentComponent
const parentComponentSpyObj = jasmine.createSpyObj('ParentComponent', ['onEventReceived']);
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [MainComponent, ParentComponent, ChildComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [FlexLayoutModule],
providers: [
// Provide the spy object for ParentComponent
{ provide: ParentComponent, useClass: parentComponentSpyObj },
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MainComponent);
mainComponent = fixture.componentInstance;
fixture.detectChanges();
});
it(`Should call onEventReceived of ParentComponent when child button is pressed`, () => {
// Given
const childComponent: ChildComponent = fixture.debugElement.query(By.directive(ChildComponent)).componentInstance;
const childComponentButton = fixture.debugElement.query(By.css('#button'));
// When
childComponentButton.triggerEventHandler('click', null);
fixture.detectChanges();
// Then
expect(parentComponentSpyObj.onEventReceived).toHaveBeenCalledTimes(1);
});
});