【问题标题】:Error during mocking the service for Angular2 application unit test模拟 Angular2 应用程序单元测试的服务时出错
【发布时间】:2016-06-23 15:30:09
【问题描述】:

我创建了一个组件,我正在尝试使用 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] 语句出现错误。删除它后,没有错误,但我需要此组件对其执行测试。

什么会导致这个注入错误?

【问题讨论】:

  • 我遇到了一些类似的问题,发现injectinjectAsync 隐藏了实例化组件的问题。当我切换到只是新组件时,问题冒泡到控制台输出,我能够诊断出缺少的 rxjs 操作员依赖性。

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


【解决方案1】:

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

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' }]) }));
  });

});

【讨论】:

    【解决方案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'])
        });
    
      });
    
    });
    

    【讨论】:

    • 原来问题有点不同。一切正常,我只是返回不正确的值。我添加了描述问题的回复。
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 2017-03-12
    相关资源
    最近更新 更多