使用 Testbed 的 angular2 测试组件出错
error with angular2 testing component with Testbed
尝试通过一个简单示例学习 angular-2 中的这个测试实用程序 TestBed
,并且遇到了我的第一个障碍。 google 或 SO 搜索未产生任何匹配示例,
所以,我有一个非常基本的组件 header
如下 -
import { Component } from '@angular/core';
@Component({
selector: 'header',
template: ''
})
export class HeaderComponent{
public title: string;
constructor(testparam: string){
this.title = 'test';
}
}
然后其规格如下 -
import { TestBed } from '@angular/core/testing';
import { HeaderComponent } from './header.component';
describe('HeaderComponent Test', () => {
let component: HeaderComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [HeaderComponent]
});
const fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
});
it('should have the component defined', () => {
expect(component).toBeDefined();
});
it('should initialize the title to test', () => {
expect(component.title).toBe('test');
});
});
running the karma test is throwing - Error: No provider for String! in karma.entry.js
karma.entry.js 基本上只是为 TestBed 设置测试环境配置,然后通过我的 spec 文件夹中的每个测试,下面是我的 karma.entry.js
require('core-js/es6');
require('core-js/es7/reflect');
require('es6-shim');
require('reflect-metadata');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('rxjs/Rx');
const browserTesting = require('@angular/platform-browser-dynamic/testing');
const coreTesting = require('@angular/core/testing');
coreTesting.TestBed.initTestEnvironment(
browserTesting.BrowserDynamicTestingModule,
browserTesting.platformBrowserDynamicTesting()
);
const context = require.context('../src', true, /\.spec\.ts$/);
context.keys().forEach(context);
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
如果我从组件 class 的构造函数中删除参数,测试通过,所以我认为我缺少一些导致 TestBed.createComponent(HeaderComponent)
无法正确编译的预配置带有字符串类型参数的组件的构造函数。
知道我可能遗漏了什么吗?
更新:
如果对任何人有帮助 -
根据@mrkosima 的回答,我更新后的组件 class 现在看起来像下面这样,单元测试现在全部通过了:)
import { Component, OpaqueToken, Inject } from '@angular/core';
export let TITLE_TOKEN = new OpaqueToken('title token');
@Component({
selector: 'header',
template: '',
providers: [{ provide: TITLE_TOKEN, useValue: 'test' }]
})
export class HeaderComponent{
public title: string;
constructor(@Inject(TITLE_TOKEN) titleParam: string){
this.title = titleParam;
}
}
你是对的,问题的根本原因在构造函数的参数中。
在组件实例化过程中Injector
尝试解析构造函数中列出的所有依赖项。 Injector
在提供商中按类型查找依赖项。
更多关于 DI 的信息:https://angular.io/docs/ts/latest/guide/dependency-injection.html
这意味着如果组件有 constructor(authService: AuthService) { }
,则 Injector
在提供商中寻找 AuthService
令牌。
你的情况也一样——你的组件依赖于String
。
但是没有任何提供者具有 String
令牌。
实际上,将基本类型列为依赖项是错误的。
应该使用 OpaqueToken
而不是
export let TITLE_TOKEN = new OpaqueToken('title token');
在模块提供者中配置令牌
providers: [{ provide: TITLE_TOKEN, useValue: 'title value' }]
比在组件中注入令牌:
constructor(@Inject(TITLE_TOKEN) title: string) {
this.title = title;
}
这是注入原语的正确用法。
这里有更多详细信息:
https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#opaquetoken
PS:要测试您的组件,应将 TITLE_TOKEN
添加到测试模块:
import {TITLE_TOKEN} from ...
TestBed.configureTestingModule({
providers: [ { provide: TITLE_TOKEN, useValue: 'test' } ]
});
然后创建测试组件并期望 title
为 'test'
。
尝试通过一个简单示例学习 angular-2 中的这个测试实用程序 TestBed
,并且遇到了我的第一个障碍。 google 或 SO 搜索未产生任何匹配示例,
所以,我有一个非常基本的组件 header
如下 -
import { Component } from '@angular/core';
@Component({
selector: 'header',
template: ''
})
export class HeaderComponent{
public title: string;
constructor(testparam: string){
this.title = 'test';
}
}
然后其规格如下 -
import { TestBed } from '@angular/core/testing';
import { HeaderComponent } from './header.component';
describe('HeaderComponent Test', () => {
let component: HeaderComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [HeaderComponent]
});
const fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
});
it('should have the component defined', () => {
expect(component).toBeDefined();
});
it('should initialize the title to test', () => {
expect(component.title).toBe('test');
});
});
running the karma test is throwing -
Error: No provider for String! in karma.entry.js
karma.entry.js 基本上只是为 TestBed 设置测试环境配置,然后通过我的 spec 文件夹中的每个测试,下面是我的 karma.entry.js
require('core-js/es6');
require('core-js/es7/reflect');
require('es6-shim');
require('reflect-metadata');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('rxjs/Rx');
const browserTesting = require('@angular/platform-browser-dynamic/testing');
const coreTesting = require('@angular/core/testing');
coreTesting.TestBed.initTestEnvironment(
browserTesting.BrowserDynamicTestingModule,
browserTesting.platformBrowserDynamicTesting()
);
const context = require.context('../src', true, /\.spec\.ts$/);
context.keys().forEach(context);
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
如果我从组件 class 的构造函数中删除参数,测试通过,所以我认为我缺少一些导致 TestBed.createComponent(HeaderComponent)
无法正确编译的预配置带有字符串类型参数的组件的构造函数。
知道我可能遗漏了什么吗?
更新:
如果对任何人有帮助 - 根据@mrkosima 的回答,我更新后的组件 class 现在看起来像下面这样,单元测试现在全部通过了:)
import { Component, OpaqueToken, Inject } from '@angular/core';
export let TITLE_TOKEN = new OpaqueToken('title token');
@Component({
selector: 'header',
template: '',
providers: [{ provide: TITLE_TOKEN, useValue: 'test' }]
})
export class HeaderComponent{
public title: string;
constructor(@Inject(TITLE_TOKEN) titleParam: string){
this.title = titleParam;
}
}
你是对的,问题的根本原因在构造函数的参数中。
在组件实例化过程中Injector
尝试解析构造函数中列出的所有依赖项。 Injector
在提供商中按类型查找依赖项。
更多关于 DI 的信息:https://angular.io/docs/ts/latest/guide/dependency-injection.html
这意味着如果组件有 constructor(authService: AuthService) { }
,则 Injector
在提供商中寻找 AuthService
令牌。
你的情况也一样——你的组件依赖于String
。
但是没有任何提供者具有 String
令牌。
实际上,将基本类型列为依赖项是错误的。
应该使用 OpaqueToken
而不是
export let TITLE_TOKEN = new OpaqueToken('title token');
在模块提供者中配置令牌
providers: [{ provide: TITLE_TOKEN, useValue: 'title value' }]
比在组件中注入令牌:
constructor(@Inject(TITLE_TOKEN) title: string) {
this.title = title;
}
这是注入原语的正确用法。
这里有更多详细信息: https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#opaquetoken
PS:要测试您的组件,应将 TITLE_TOKEN
添加到测试模块:
import {TITLE_TOKEN} from ...
TestBed.configureTestingModule({
providers: [ { provide: TITLE_TOKEN, useValue: 'test' } ]
});
然后创建测试组件并期望 title
为 'test'
。