Angular2 - 在组件中测试ngOninit

时间:2016-04-17 15:28:42

标签: unit-testing angular angular2-directives

我有一个包含以下代码的列表组件:

///<reference path="../../node_modules/angular2/typings/browser.d.ts"/>
import { Component, OnInit } from 'angular2/core';
import { ROUTER_DIRECTIVES } from 'angular2/router';

import { Employee } from '../models/employee';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';

@Component({
  selector: 'employee-list',
  template: `
    <ul class="employees">
  <li *ngFor="#employee of employees">
    <a [routerLink]="['EmployeeDetail', {id: employee.id}]">
      <span class="badge">{{employee.id}}</span>
      {{employee.name}}
    </a>
  </li>
</ul>
  `,
  directives: [ROUTER_DIRECTIVES],
  providers: [EmployeeListServiceComponent]
})

export class EmployeeListComponent implements OnInit {
  public employees: Employee[];
  public errorMessage: string;

  constructor(
    private _listingService: EmployeeListServiceComponent
  ){}

  ngOnInit() {
    this._listingService.getEmployees().subscribe(
                     employees => this.employees = employees,
                     error =>  this.errorMessage = <any>error
                   );
  }
}

我希望为ngOninit钩子编写单元测试。我写了以下测试:

/// <reference path="../../typings/main/ambient/jasmine/jasmine.d.ts" />

import {
    it,
    describe,
    expect,
    TestComponentBuilder,
    injectAsync,
    setBaseTestProviders,
    beforeEachProviders,
} from "angular2/testing";
import { Component, provide, ApplicationRef, OnInit } from "angular2/core";
import {
    TEST_BROWSER_PLATFORM_PROVIDERS,
    TEST_BROWSER_APPLICATION_PROVIDERS
} from "angular2/platform/testing/browser";
import {
    ROUTER_DIRECTIVES,
    ROUTER_PROVIDERS,
    ROUTER_PRIMARY_COMPONENT,
    APP_BASE_HREF
} from 'angular2/router';
import {XHRBackend, HTTP_PROVIDERS} from "angular2/http";
import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref';
import {MockBackend } from "angular2/src/http/backends/mock_backend";
import {Observable} from 'rxjs/Rx';
import 'rxjs/Rx';

import { Employee } from '../models/employee';
import { EmployeeListComponent } from './list.component';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';


class MockEmployeeListServiceComponent {

    getEmployees () {
        return Observable.of([
            {
                "id": 1,
                "name": "Abhinav Mishra"
            }
        ]);
    }
}


@Component({
    template: '<employee-list></employee-list>',
    directives: [EmployeeListComponent],
    providers: [MockEmployeeListServiceComponent]
})
class TestMyList {}


describe('Employee List Tests', () => {
    setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);

    beforeEachProviders(() => {
        return [
            ROUTER_DIRECTIVES,
            ROUTER_PROVIDERS,
            HTTP_PROVIDERS,
            provide(EmployeeListServiceComponent, {useClass: MockEmployeeListServiceComponent}),
            provide(XHRBackend, {useClass: MockBackend}),
            provide(APP_BASE_HREF, {useValue: '/'}),
            provide(ROUTER_PRIMARY_COMPONENT, {useValue: EmployeeListComponent}),
            provide(ApplicationRef, {useClass: MockApplicationRef})
        ]
    });

    it('Should be true',
        injectAsync([TestComponentBuilder], (tcb) => {
            return tcb
                .createAsync(TestMyList)
                .then((fixture) => {
                    fixture.detectChanges();
                    var compiled = fixture.debugElement.nativeElement;
                    console.log(compiled.innerHTML);
                    expect(true).toBe(true);
                });
        })
    );
});

但是,测试中console.log的输出为空ul标记,如下所示:

 '<employee-list>
    <ul class="employees">
  <!--template bindings={}-->
</ul>
  </employee-list>'

有人能建议我为组件钩子编写单元测试的正确方法吗?

injectAsync块中模拟http请求,如下所示:

backend.connections.subscribe(
                (connection:MockConnection) => {
                    var options = new ResponseOptions({
                        body: [
                            {
                                "id": 1,
                                "name": "Abhinav Mishra"
                            }
                        ]
                    });

                    var response = new Response(options);

                    connection.mockRespond(response);
                }
            );

但是现在我收到另一个错误如下:

Failed: EXCEPTION: Component "EmployeeListComponent" has no route config. in [['EmployeeDetail', {id: employee.id}] in EmployeeListComponent@3:7]
        ORIGINAL EXCEPTION: Component "EmployeeListComponent" has no route config.
        ORIGINAL STACKTRACE:
        Error: Component "EmployeeListComponent" has no route config.

1 个答案:

答案 0 :(得分:3)

如果您在ngOnInit()中调用异步代码,则在执行console.log(...)时无法假定它已完成。 this.employees仅在传递给subscribe(...)的回调在响应到达后被调用时设置。

如果您使用MockBackend,您可以控制响应,并且在响应通过后,您必须再次运行fixture.detectChanges()以使组件使用更新的数据重新呈现,然后您可以阅读{{ 1}}并期望它包含渲染的内容。