使用 @ViewChild 对 angular 5 个组件进行单元测试
Unit testing angular 5 component with @ViewChild
我正在使用 angular 5.2.0。我有一个子组件
import { Component } from '@angular/core';
@Component({
template: `<div><div></div></div>`,
})
export class ChildComponent {
public childMethod() {
...
}
}
和通过 ViewChild
访问子组件的父组件
import { Component, ViewChild } from "@angular/core";
import { ChildComponent } from "child.component";
@Component({
template: `
<child-component #child>
<child-component></child-component>
</child-component>
`,
})
export class ParentComponent {
@ViewChild("child") child: ChildComponent;
public parentMethod() {
this.child.childMethod();
}
}
我想要一个单元测试来证明 parentMethod
的调用会导致 childMethod
的调用。我有以下内容:
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ChildComponent } from "./child.component";
import { ParentComponent } from "./parent.component";
describe("ParentComponent", () => {
let component: Parentcomponent;
let fixture: ComponentFixture<Parentcomponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ParentComponent, ChildComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TaskListPaginatorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should invoke childMethod when parentMethod is invoked", () => {
const childMethodSpy: jasmine.Spy = spyOn(component.child, "childMethod");
component.parentMethod();
expect(childMethodSpy).toHaveBeenCalled();
});
});
然而,这不起作用,我得到 Error: <spyOn> : could not find an object to spy upon for childMethod()
。
此外,这不是单元测试,因为我使用的是真正的 ChildComponent 而不是模拟。我尝试创建一个 MockChildComponent 并将其添加到 declarations
和 export
但我得到了相同的结果。有帮助吗?
我知道有类似的 post,但它们是针对不同版本的 angular,它们没有帮助。
你可以这样做。
像这样为 ChildComponent
创建一个间谍对象。
const childComponent = jasmine.createSpyObj('ChildComponent', ['childMethod']);
然后在测试中,将组件的childComponent属性设置为你创建的spy
component.childComponent = childComponent;
您的测试文件应如下所示。
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ChildComponent } from "./child.component";
import { ParentComponent } from "./parent.component";
describe("ParentComponent", () => {
let component: ParentComponent;
let fixture: ComponentFixture<ParentComponent>;
const childComponent = jasmine.createSpyObj("ChildComponent", [
"childMethod",
]);
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ParentComponent, ChildComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ParentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should invoke childMethod when parentMethod is invoked", () => {
component.childComponent = childComponent;
component.parentMethod();
expect(childComponent.childMethod).toHaveBeenCalled();
});
});
您可以模拟 ChildComponent,这样您就可以单独测试 ParentComponent,而不需要手动分配 ChildComponent。
如果 ParentComponent.childComponent 是私有的,这是必需的,如果 ChildComponent 有很多依赖项,这几乎是必需的。
您的测试文件应如下所示:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChildComponent } from './child.component';
import { ParentComponent } from './parent.component';
const childMethodSpỳ = jasmine.createSpy('childMethod');
class ChildStubComponent {
childMethod = childMethodSpỳ;
}
@Component({
selector: 'child-component',
template: '',
providers: [{ provide: ChildComponent, useClass: ChildStubComponent }]
})
describe('ParentComponent', () => {S
let component: ParentComponent;
let fixture: ComponentFixture<ParentComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ ParentComponent, ChildStubComponent ]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ParentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should invoke childMethod when parentMethod is invoked', () => {
component.parentMethod();
expect(childMethodSpỳ).toHaveBeenCalled();
});
});
学分:
来自 Angular inDepth 的想法。
基于@Anuradha Gunasekara 的回答。
或者,覆盖此类代码的快速简便方法....
如果 .ts 文件是这样的:
@ViewChild('datePicker') myDatePicker: AngularMyDatePickerDirective
然后在 spec.ts 文件里面的 it() 块中,你可以添加如下内容:
component.myDatePicker = { toggleCalender: () => Promise.resolve()} as unknown as AngularMyDatePickerDirective;
我正在使用 angular 5.2.0。我有一个子组件
import { Component } from '@angular/core';
@Component({
template: `<div><div></div></div>`,
})
export class ChildComponent {
public childMethod() {
...
}
}
和通过 ViewChild
import { Component, ViewChild } from "@angular/core";
import { ChildComponent } from "child.component";
@Component({
template: `
<child-component #child>
<child-component></child-component>
</child-component>
`,
})
export class ParentComponent {
@ViewChild("child") child: ChildComponent;
public parentMethod() {
this.child.childMethod();
}
}
我想要一个单元测试来证明 parentMethod
的调用会导致 childMethod
的调用。我有以下内容:
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ChildComponent } from "./child.component";
import { ParentComponent } from "./parent.component";
describe("ParentComponent", () => {
let component: Parentcomponent;
let fixture: ComponentFixture<Parentcomponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ParentComponent, ChildComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TaskListPaginatorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should invoke childMethod when parentMethod is invoked", () => {
const childMethodSpy: jasmine.Spy = spyOn(component.child, "childMethod");
component.parentMethod();
expect(childMethodSpy).toHaveBeenCalled();
});
});
然而,这不起作用,我得到 Error: <spyOn> : could not find an object to spy upon for childMethod()
。
此外,这不是单元测试,因为我使用的是真正的 ChildComponent 而不是模拟。我尝试创建一个 MockChildComponent 并将其添加到 declarations
和 export
但我得到了相同的结果。有帮助吗?
我知道有类似的 post,但它们是针对不同版本的 angular,它们没有帮助。
你可以这样做。
像这样为 ChildComponent
创建一个间谍对象。
const childComponent = jasmine.createSpyObj('ChildComponent', ['childMethod']);
然后在测试中,将组件的childComponent属性设置为你创建的spy
component.childComponent = childComponent;
您的测试文件应如下所示。
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ChildComponent } from "./child.component";
import { ParentComponent } from "./parent.component";
describe("ParentComponent", () => {
let component: ParentComponent;
let fixture: ComponentFixture<ParentComponent>;
const childComponent = jasmine.createSpyObj("ChildComponent", [
"childMethod",
]);
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ParentComponent, ChildComponent],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ParentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should invoke childMethod when parentMethod is invoked", () => {
component.childComponent = childComponent;
component.parentMethod();
expect(childComponent.childMethod).toHaveBeenCalled();
});
});
您可以模拟 ChildComponent,这样您就可以单独测试 ParentComponent,而不需要手动分配 ChildComponent。
如果 ParentComponent.childComponent 是私有的,这是必需的,如果 ChildComponent 有很多依赖项,这几乎是必需的。
您的测试文件应如下所示:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChildComponent } from './child.component';
import { ParentComponent } from './parent.component';
const childMethodSpỳ = jasmine.createSpy('childMethod');
class ChildStubComponent {
childMethod = childMethodSpỳ;
}
@Component({
selector: 'child-component',
template: '',
providers: [{ provide: ChildComponent, useClass: ChildStubComponent }]
})
describe('ParentComponent', () => {S
let component: ParentComponent;
let fixture: ComponentFixture<ParentComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ ParentComponent, ChildStubComponent ]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ParentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should invoke childMethod when parentMethod is invoked', () => {
component.parentMethod();
expect(childMethodSpỳ).toHaveBeenCalled();
});
});
学分: 来自 Angular inDepth 的想法。 基于@Anuradha Gunasekara 的回答。
或者,覆盖此类代码的快速简便方法....
如果 .ts 文件是这样的:
@ViewChild('datePicker') myDatePicker: AngularMyDatePickerDirective
然后在 spec.ts 文件里面的 it() 块中,你可以添加如下内容:
component.myDatePicker = { toggleCalender: () => Promise.resolve()} as unknown as AngularMyDatePickerDirective;