模拟Angular2应用程序单元测试服务时出错

时间:2016-03-09 10:08:05

标签: unit-testing typescript angular webpack karma-jasmine

我创建了一个我尝试使用Karma和Jasmine进行测试的组件。一切都适用于没有DI注入服务的其他组件。但是这个抛出一个没有任何消息的错误,只是堆栈。

这是组件:

import {Component} from 'angular2/core';

import {Application} from './application';
import {ApplicationsService} from './applications.service';

@Component({
    selector: 'applications-selector',
    styles: [require('./applications-selector.scss')],
    template: require('./applications-selector.html'),
    providers: [ApplicationsService]
})

export class ApplicationsSelectorComponent {
    applications: Application[];
    selectedWeek: number;
    selectedApplications: Application[];
    selectedCycle: string;

    constructor(private _applicationsService: ApplicationsService) {
        this.getApplications();
    }

    getApplications() {
        this._applicationsService.getApplications().then(applications => this.applications = applications);
    }
}

以下是此组件的单元测试:

import {
  it,
  inject,
  injectAsync,
  describe,
  beforeEachProviders,
  TestComponentBuilder
} from 'angular2/testing';
import {provide} from 'angular2/core';

import {ApplicationsSelectorComponent} from './applications-selector.component';
import {ApplicationsService} from './applications.service';

class ApplicationsServiceMock {
  getApplications() {
      return ['ABC', 'XYZ'];
  }
}

describe('ApplicationsSelectorComponent', () => {
    beforeEachProviders(() => [
        provide(ApplicationsService, { useClass: ApplicationsServiceMock }),
        ApplicationsSelectorComponent
    ]);

    it('should have empty default values', inject([ApplicationsSelectorComponent], (component) => {
        expect(component.selectedWeek).toBe(undefined);
        expect(component.selectedApplications).toBe(undefined);
        expect(component.selectedCycle).toBe(undefined);
    }));
}); 

这是我在运行此测试时得到的错误:

ApplicationsSelectorComponent
    × should have empty default values
      PhantomJS 2.1.1 (Windows 7 0.0.0)
    _instantiateProvider@d:/git/gatekeeper/web/spec-bundle.js:11896:38 <- webpack:///angular2/src/core/di/injector.ts:770:31
    _new@d:/git/gatekeeper/web/spec-bundle.js:11885:42 <- webpack:///angular2/src/core/di/injector.ts:759:37
    getObjByKeyId@d:/git/gatekeeper/web/spec-bundle.js:11495:55 <- webpack:///angular2/src/core/di/injector.ts:356:44
    _getByKeyDefault@d:/git/gatekeeper/web/spec-bundle.js:12083:51 <- webpack:///angular2/src/core/di/injector.ts:977:44
    _getByKey@d:/git/gatekeeper/web/spec-bundle.js:12029:42 <- webpack:///angular2/src/core/di/injector.ts:914:35
    get@d:/git/gatekeeper/web/spec-bundle.js:11704:31 <- webpack:///angular2/src/core/di/injector.ts:577:26
    d:/git/gatekeeper/web/spec-bundle.js:9128:74 <- webpack:///angular2/src/testing/test_injector.ts:151:52
    map@[native code]
    apply@[native code]
    call@[native code]
    call@[native code]
    map@d:/git/gatekeeper/web/spec-bundle.js:2377:21 <- webpack:///~/es6-shim/es6-shim.js:1113:0
    execute@d:/git/gatekeeper/web/spec-bundle.js:9128:39 <- webpack:///angular2/src/testing/test_injector.ts:151:34
    execute@d:/git/gatekeeper/web/spec-bundle.js:9017:27 <- webpack:///angular2/src/testing/test_injector.ts:42:22
    d:/git/gatekeeper/web/spec-bundle.js:8393:58 <- webpack:///angular2/src/testing/testing.ts:137:49
    _instantiate@d:/git/gatekeeper/web/spec-bundle.js:12003:87 <- webpack:///angular2/src/core/di/injector.ts:883:67

inject([ApplicationsSelectorComponent] 语句中发生错误。一旦删除它,就没有错误,但是我需要这个组件来对它执行测试。

什么会导致这种注射错误?

2 个答案:

答案 0 :(得分:2)

您似乎尝试以与无效的提供商相同的方式注入组件。

以下是特定组件的模拟提供程序的完整最小示例:

class ApplicationsService {
  getApplications() {
    return ['ABC'];
  }
}

class ApplicationsServiceMock {
  getApplications() {
    return ['ABC', 'XYZ'];
  }
}

@Component({
  selector: 'apps',
  template: '',
  providers: [ApplicationsService]
})
class ApplicationsSelectorComponent {
  constructor(private apps: ApplicationsService) {}
}

describe('App', () => {

  describe('ApplicationsSelectorComponent', () => {
    beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
      return tcb
        .overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
        .createAsync(ApplicationsSelectorComponent)
        .then((componentFixture: any) => {
          this.component = componentFixture;
        });
    }));

    it('should have empty default values', () => {
      expect(this.component.componentInstance.apps.getApplications()).toEqual(['ABC', 'XYZ'])
    });

  });

});

答案 1 :(得分:0)

最后,事实证明所有设置都是正确的,但我只是从ApplicationsServiceMock返回了错误的值。基本服务正在返回Promise,我在模拟中返回了一个值数组。这就是为什么当从this._applicationsService.getApplications().then(applications => this.applications = applications);执行此行constructor时,无法找到阵列上的然后方法。测试失败了。
一旦我从我的模拟中修复了返回值,一切正常 这是我测试的工作代码:

import {
    it,
    beforeEach,
    injectAsync,
    describe,
    TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';

import {Application} from './application';
import {ApplicationsService} from './applications.service';
import {ApplicationsSelectorComponent} from './applications-selector.component';


class ApplicationsServiceMock {
    getApplications() {
        return Promise.resolve([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]);
    }
}


describe('ApplicationsSelectorComponent', () => {
  beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    return tcb
      .overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
      .createAsync(ApplicationsSelectorComponent)
      .then((componentFixture: any) => {
        this.component = componentFixture;
      });
  }));

  it('should have empty default values', () => {
      expect(this.component.componentInstance._applicationsService.getApplications().then(apps => { apps.toEqual([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]) }));
  });

});