Angular 9 单元测试:如何模拟导入测试组件?
Angular 9 Unit Test: how to mock import of tested component?
所以我目前正在为 Angular 9 组件编写 Jasmine/Karma 单元测试。
我的应用程序如何工作的简短摘要:
我用 D3 编写了一些 Funnel
,它在类似漏斗的图表中显示给定的数据。然后我写了一个 FunnelComponent
包含这个 Funnel
并且还在实际图表旁边显示了一些元信息。
这是我要测试的组件:
funnel.component.ts
import { Component } from '@angular/core';
import { Funnel } from './d3charts/funnel.ts';
import { FunnelData } from './funnel.data';
@Component({
selector: 'v7-funnel-component',
templateUrl: './funnel.html'
})
export class FunnelComponent {
private funnel: Funnel = null;
constructor() {}
public createFunnel(funnelData: FunnelData): void {
this.funnel = new Funnel();
this.funnel.setData(funnelData);
this.funnel.draw();
}
}
这是我对该组件的 karma-jasmine 单元测试:
funnel.component.spec.ts
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { } from 'jasmine';
import { FunnelComponent } from './funnel.component';
import { Component } from '@angular/core';
import { FunnelData } from './funnel.data';
import { Funnel } from './d3charts/funnel.ts';
@Component({selector: 'funnel', template: ''})
class FunnelStub {
private data: FunnelData = null;
public setData(data: FunnelData): void
{this.data = data;}
{}
public draw(): void
{}
public update(funnelData: FunnelData): void
{}
}
/**
* Testing class for FunnelComponent.
*/
describe('Component: Funnel', () => {
let component: FunnelComponent;
let fixture: ComponentFixture<FunnelComponent>;
beforeEach(async(() => {
TestBed
.configureTestingModule({
declarations: [
FunnelComponent,
FunnelStub
],
providers: [
{ provide: Funnel, useValue: FunnelStub}
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(FunnelComponent);
component = fixture.componentInstance;
});
}));
it('#createFunnel should set data of funnel. Filled data should set filled funnel.', () => {
expect(component["funnel"]).toBeNull();
let exampleFunnelData = new FunnelData("testcaption", "testdescription", 8);
component.createFunnel(exampleFunnelData);
expect(component["funnel"]).toBeDefined();
expect(component["funnel"]["data"]).toBeDefined();
expect(component.data.caption).toEqual("testcaption");
expect(component.data.description).toEqual("testsubtext");
expect(component.data.value).toEqual(8);
});
});
我想在这里测试createFunnel
方法。
但我不希望我的 createFunnel 方法将真实的 Funnel
分配给 this.funnel
,而是使用我的 FunnelStub
。
知道怎么做吗?
将 { provide: Funnel, useValue: FunnelStub}
添加到我的供应商数组没有帮助:(
此致,
塞巴斯蒂安
这不起作用,因为 Funnel 不是提供商:
providers: [
{ provide: Funnel, useValue: FunnelStub}
]
对测试最有帮助的是创建用于创建漏斗的服务。
export abstract class FunnelProvider {
abstract createFunnel(): Funnel;
}
此服务可以有 2 种实现,一种是您在应用中使用的实现,另一种是您在测试中使用的实现。
@Injectable()
export class DefaultFunnelProvider {
createFunnel() {
return new Funnel(); // Return real funnel object.
}
}
@Injectable()
export class MockFunnelProvider {
createFunnel() {
// Return stub funnel. Assuming that they share the same interface.
return new FunnelStub() as Funnel;
}
}
现在您必须在 FunnelModule(声明 FunnelComponent 的模块)中定义 DefaultFunnelProvider
:
@NgModule({
... // other stuff
providers: [{provide: FunnelProvider, useClass: DefaultFunnelProvider}]
})
export class FunnelModule {}
然后在 FunnelComponent 中注入 FunnelProvider 并使用它来创建漏斗:
export class FunnelComponent {
private funnel: Funnel = null;
constructor(private funnelProvider: FunnelProvider) {}
public createFunnel(funnelData: FunnelData): void {
this.funnel = this.funnelProvider.createFunnel();
this.funnel.setData(funnelData);
this.funnel.draw();
}
}
很多工作,但现在很酷的是,您可以在 TestBed 中注入 FunnelProvider 的 Mock 实现:
TestBed
.configureTestingModule({
declarations: [
FunnelComponent,
FunnelStub
],
providers: [
{ provide: FunnelProvider, useValue: MockFunnelProvider }
]
})
现在调用 funnelProvider.createFunnel 时,它不会 return 一个真正的漏斗,而是你的漏斗存根。
如果在测试期间必须这样做,您可以将组件漏斗字段转换为 FunnelStub(例如,如果它有一些特殊方法):
const funnelStub = component.funnel as FunnelStub;
所以我目前正在为 Angular 9 组件编写 Jasmine/Karma 单元测试。
我的应用程序如何工作的简短摘要:
我用 D3 编写了一些 Funnel
,它在类似漏斗的图表中显示给定的数据。然后我写了一个 FunnelComponent
包含这个 Funnel
并且还在实际图表旁边显示了一些元信息。
这是我要测试的组件:
funnel.component.ts
import { Component } from '@angular/core';
import { Funnel } from './d3charts/funnel.ts';
import { FunnelData } from './funnel.data';
@Component({
selector: 'v7-funnel-component',
templateUrl: './funnel.html'
})
export class FunnelComponent {
private funnel: Funnel = null;
constructor() {}
public createFunnel(funnelData: FunnelData): void {
this.funnel = new Funnel();
this.funnel.setData(funnelData);
this.funnel.draw();
}
}
这是我对该组件的 karma-jasmine 单元测试:
funnel.component.spec.ts
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { } from 'jasmine';
import { FunnelComponent } from './funnel.component';
import { Component } from '@angular/core';
import { FunnelData } from './funnel.data';
import { Funnel } from './d3charts/funnel.ts';
@Component({selector: 'funnel', template: ''})
class FunnelStub {
private data: FunnelData = null;
public setData(data: FunnelData): void
{this.data = data;}
{}
public draw(): void
{}
public update(funnelData: FunnelData): void
{}
}
/**
* Testing class for FunnelComponent.
*/
describe('Component: Funnel', () => {
let component: FunnelComponent;
let fixture: ComponentFixture<FunnelComponent>;
beforeEach(async(() => {
TestBed
.configureTestingModule({
declarations: [
FunnelComponent,
FunnelStub
],
providers: [
{ provide: Funnel, useValue: FunnelStub}
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(FunnelComponent);
component = fixture.componentInstance;
});
}));
it('#createFunnel should set data of funnel. Filled data should set filled funnel.', () => {
expect(component["funnel"]).toBeNull();
let exampleFunnelData = new FunnelData("testcaption", "testdescription", 8);
component.createFunnel(exampleFunnelData);
expect(component["funnel"]).toBeDefined();
expect(component["funnel"]["data"]).toBeDefined();
expect(component.data.caption).toEqual("testcaption");
expect(component.data.description).toEqual("testsubtext");
expect(component.data.value).toEqual(8);
});
});
我想在这里测试createFunnel
方法。
但我不希望我的 createFunnel 方法将真实的 Funnel
分配给 this.funnel
,而是使用我的 FunnelStub
。
知道怎么做吗?
将 { provide: Funnel, useValue: FunnelStub}
添加到我的供应商数组没有帮助:(
此致, 塞巴斯蒂安
这不起作用,因为 Funnel 不是提供商:
providers: [
{ provide: Funnel, useValue: FunnelStub}
]
对测试最有帮助的是创建用于创建漏斗的服务。
export abstract class FunnelProvider {
abstract createFunnel(): Funnel;
}
此服务可以有 2 种实现,一种是您在应用中使用的实现,另一种是您在测试中使用的实现。
@Injectable()
export class DefaultFunnelProvider {
createFunnel() {
return new Funnel(); // Return real funnel object.
}
}
@Injectable()
export class MockFunnelProvider {
createFunnel() {
// Return stub funnel. Assuming that they share the same interface.
return new FunnelStub() as Funnel;
}
}
现在您必须在 FunnelModule(声明 FunnelComponent 的模块)中定义 DefaultFunnelProvider
:
@NgModule({
... // other stuff
providers: [{provide: FunnelProvider, useClass: DefaultFunnelProvider}]
})
export class FunnelModule {}
然后在 FunnelComponent 中注入 FunnelProvider 并使用它来创建漏斗:
export class FunnelComponent {
private funnel: Funnel = null;
constructor(private funnelProvider: FunnelProvider) {}
public createFunnel(funnelData: FunnelData): void {
this.funnel = this.funnelProvider.createFunnel();
this.funnel.setData(funnelData);
this.funnel.draw();
}
}
很多工作,但现在很酷的是,您可以在 TestBed 中注入 FunnelProvider 的 Mock 实现:
TestBed
.configureTestingModule({
declarations: [
FunnelComponent,
FunnelStub
],
providers: [
{ provide: FunnelProvider, useValue: MockFunnelProvider }
]
})
现在调用 funnelProvider.createFunnel 时,它不会 return 一个真正的漏斗,而是你的漏斗存根。
如果在测试期间必须这样做,您可以将组件漏斗字段转换为 FunnelStub(例如,如果它有一些特殊方法):
const funnelStub = component.funnel as FunnelStub;