使用 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'