Kim*_*tes 4 javascript testbed angular
我有一个组件,我正在尝试使用TestBed进行设置和测试.
该组件包含一个类,该构造函数中的参数是一个接口,而不是具体的类.我选择使用的任何类(无论是真实的,还是用于单元测试的mok)都满足此接口.但是,当我构建在TestBed中使用此服务的组件时,我无法弄清楚如何将该参数定义到TestBed配置.
以下是组件的TestBed配置:
describe('PanelContentAreaComponent', () => {
let component: PanelContentAreaComponent;
let fixture: ComponentFixture<PanelContentAreaComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ PanelContentAreaComponent
],
providers:[
MenuCommandService, ProcedureDataService, IOpenService],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
Run Code Online (Sandbox Code Playgroud)
在TestBed中构造有问题的服务是ProcedureDataService.它的定义如下:
@Injectable()
export class ProcedureDataService {
serverOpenFile: OpenFile;
constructor(private _openService: IOpenService) {
this.serverOpenFile = emptyFileStatus;
}
Run Code Online (Sandbox Code Playgroud)
构造函数中的一个参数ProcedureDataService是IOpenService其定义为:
export interface IOpenService {
openFile(fileType: string, dataType: string, filePath: string) ;
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这是一个接口,而不是具体的类.
在我的服务单元测试中,我们通过如下实现来模拟IOpenService:
export class mockOpenService implements IOpenService{
constructor(){}
openFile(fileType: string, dataType: string, filePath: string) {
let fileContent: OpenFile;
...
...
[fake the data with mok junk]
...
fileContent = {
'filePath': filePath,
'fileName': name,
'openSuccess': isSuccess,
'error': errorMsg,
'fileData': jsonData
};
return Observable.of(fileContent);
}
}
Run Code Online (Sandbox Code Playgroud)
这在ProcedureDataService服务单元测试中非常有用.当然,在实际代码中,我们使用完全实现的文件打开服务来实现IOpenService,该服务可以正确地获取数据.
但是在尝试在组件内使用此服务时,我收到以下错误:
PanelContentAreaComponent should create FAILED
Failed: IOpenService is not defined
ReferenceError: IOpenService is not defined
Run Code Online (Sandbox Code Playgroud)
这是有道理的,所以我试图弄清楚如何告诉TestBed我有一个我希望使用的IOpenService的具体类实现.我试过这个,但它失败了:
describe('PanelContentAreaComponent', () => {
let component: PanelContentAreaComponent;
let fixture: ComponentFixture<PanelContentAreaComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ PanelContentAreaComponent
],
providers:[
{provide: IOpenService, useClass: mockOpenService},
MenuCommandService, ProcedureDataService, IOpenService],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
Run Code Online (Sandbox Code Playgroud)
编译器告诉我:
(31,19): error TS2693: 'IOpenService' only refers to a type, but is being used as a value here.
Run Code Online (Sandbox Code Playgroud)
我仍然得到:
PanelContentAreaComponent should create FAILED
Failed: IOpenService is not defined
ReferenceError: IOpenService is not defined
Run Code Online (Sandbox Code Playgroud)
那么我如何指示TestBed我有一个特定的class(mockOpenService)实现接口参数(IOpenService)所需的service(ProcedureDataService)被提供来测试这个组件(PanelContentAreaComponent)?
接口不能用作令牌.这在Angular docs DI Chapter Dependency injection tokens中有解释
TypeScript接口不是有效的令牌
Run Code Online (Sandbox Code Playgroud)export interface AppConfig { apiEndpoint: string; title: string; } export const HERO_DI_CONFIG: AppConfig = { apiEndpoint: 'api.heroes.com', title: 'Dependency Injection' };该
HERO_DI_CONFIG常数具有一个接口,AppConfig.不幸的是,我们不能使用TypeScript接口作为令牌:Run Code Online (Sandbox Code Playgroud)// FAIL! Can't use interface as provider token [{ provide: AppConfig, useValue: HERO_DI_CONFIG })] // FAIL! Can't inject using the interface as the parameter type constructor(private config: AppConfig){ }如果我们习惯于强类型语言中的依赖注入,那么这似乎很奇怪,其中接口是首选的依赖项查找键.
这不是Angular的错.接口是TypeScript设计时工件.JavaScript没有接口.TypeScript接口从生成的JavaScript中消失.Angular没有留下接口类型信息以便在运行时查找.
文档继续解释你应该创建一个OpaqueToken.
Run Code Online (Sandbox Code Playgroud)import { OpaqueToken } from '@angular/core'; export let APP_CONFIG = new OpaqueToken('app.config'); providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }] constructor(@Inject(APP_CONFIG) config: AppConfig) { this.title = config.title; }
这个例子没问题,但在我们的服务案例中,这不是最优雅的解决方案.就个人而言,我认为更优雅的解决方案是不使用接口来完成服务.而是使用抽象类.抽象类被转换为实际代码,就像普通类一样.所以你可以用它作为代币
export abstract class IOpenService {
abstract openFile(fileType: string, dataType: string, filePath: string): any ;
}
class OpenService extends IOpenService {
openFile(fileType: string, dataType: string, filePath: string): any {
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以做到
{ provide: IOpenService, useClass: OpenService }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1935 次 |
| 最近记录: |