7

尝试TestBed通过一个简单的示例在 angular-2 中学习此测试实用程序,并遇到了我的第一个阻止程序。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');
    });
});

运行业力测试正在抛出 -Error: No provider for String! in karma.entry.js

karma.entry.js 基本上只是为 TestBed 设置测试环境配置,然后通过我的规范文件夹中的每个测试,下面是我的 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;

如果我从组件类的构造函数中删除参数,则测试通过,所以我认为我缺少一些预配置,导致TestBed.createComponent(HeaderComponent)无法使用字符串类型参数正确编译组件的构造函数。

任何线索我可能会错过什么?


更新:

如果它对任何人都有帮助 - 基于@mrkosima 的回答,我更新的组件类现在如下所示,并且单元测试现在都通过了:)

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;
    }
}
4

1 回答 1

6

您是对的,构造函数参数中问题的根本原因是正确的。

在组件实例化期间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'.

于 2017-02-12T19:55:57.303 回答