Angular JS嵌套服务单元测试

时间:2016-08-02 17:38:22

标签: angularjs unit-testing jasmine ecmascript-6

我整个下午都在尝试为正常工作的服务编写单元测试,但没有成功。问题来自注入的依赖项,因为我有另一个服务通过单元测试(它没有依赖项)。

服务就是这个



import angular from 'angular';

export class IPMAService {
  /*@ngInject*/
  constructor($http, localStorageService, appConfig, locationStorageKey) {
    debugger;
    this.$http = $http;
    this.localStorage = localStorageService;
    this.appConfig = appConfig;
    this.locationStorageKey = locationStorageKey;
    if (Object.keys(this.localStorage.get(locationStorageKey)).length < 1) {
      console.log("IPMAService - Initialization (locations not present in local storage)");
      this._getLocationsFromService();
    }
  }

  getLocations() {
    console.log("IPMAService - Get Locations");   
    var locations = this.localStorage.get(this.locationStorageKey);
    if(!locations){
      return this._getLocationsFromService();
    }
    return locations;
  };

  _getLocationsFromService(){
      var _self = this;
      this.$http({
        method: 'GET',
        url: this.appConfig.ipmaWebServices.locations
      }).then((response) => {
        _self.localStorage.set(_self.locationStorageKey, response.data);
        console.log("IPMAService - Saved locations.json to local storage with key: " + _self.locationStorageKey);
        return response;
      })
      .catch((response) => {
        console.log("IPMAService - Erro no acesso à api do IPMA: " + _self.appConfig.ipmaWebServices.locations);
      })
  }
}

export default angular.module('services.ipmaService', [])
  .service('ipmaService', IPMAService)
  .name;
&#13;
&#13;
&#13;

我阅读了很多关于单元测试的内容,但我似乎无法让它发挥作用。这是我的最后一次尝试(甚至不是基本的.toBeDefined(),因为它在inject函数中崩溃了:&#34; TypeError:无法将undefined或null转换为object&#34;):

&#13;
&#13;
'use strict';

import serviceModule from './IPMAService.service';
import LocalStorageModule from 'angular-local-storage';
import constantsModule from '../../app/app.constants';

describe('Service: IPMAService', function () {
    beforeEach(angular.mock.module(serviceModule));
    beforeEach(angular.mock.module(LocalStorageModule));
    beforeEach(angular.mock.module(constantsModule));

    var localStorageService2, service, httpBackend, ipmawebservices, locationStoreKey2;

    beforeEach(inject(function (ipmaService, _$http_, localStorageService, appConfig, locationStoreKey) {
        service = ipmaService;
        httpBackend = _$http_;
        localStorageService2 = localStorageService;
        ipmawebservices = appConfig;
        locationStoreKey2 = locationStorageKey;

    }));

    it ('should be loaded', function() {
        expect(service).toBeDefined();
    });
});
&#13;
&#13;
&#13;

另外......在我通过/工作这个基本测试后,我想知道如何测试 getLocations 方法,因为它依赖于 _getLocationsFromService 方法和 localStorage (我想我必须使用茉莉花的SpyOn,但有点帮助会很棒)。

提前致谢。

修改

这是我最后的解决方案,混合了已接受的答案和更多的研究。希望它可以帮助将来对单元测试感到绝望的人。

注意:我从服务

中删除了locationStorageKey依赖项

&#13;
&#13;
'use strict';

import serviceModule, { IPMAService } from './IPMAService.service';
import LocalStorageModule from 'angular-local-storage';
import constantsModule from '../../app/app.constants';

describe('Service: IPMAService', function () {
    var mockDependency, appConfigDependency, service,
    locationsObject = [{ local: "Lisboa", latitude: 33, longitude: 10 },{ local: "Porto", latitude: 36, longitude: 9 }];
    beforeEach(angular.mock.module(serviceModule));

    beforeEach(function () {

        mockDependency = {
            get: function () {
                return locationsObject;
            }
        };

        appConfigDependency = {

        };

        angular.mock.module(function ($provide) {
            $provide.value('localStorageService', mockDependency);
        });

        angular.mock.module(function ($provide) {
            $provide.constant('appConfig', appConfigDependency);
        });

    }); 

    beforeEach(() => {
        spyOn(IPMAService.prototype, '_getLocationsFromService').and.returnValue(locationsObject);
    });

    it('should return location object', inject(function (ipmaService) {
        expect(ipmaService.getLocations()).toBe(locationsObject);
    }));


});
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

这个问题包含一个问题。嵌套服务不应该被测试。单元测试是关于测试一个单元,一次一个。一项服务(ipmaService)经过测试,其他服务被模拟。

此列表

beforeEach(angular.mock.module(serviceModule));
beforeEach(angular.mock.module(LocalStorageModule));
beforeEach(angular.mock.module(constantsModule));

应该成为

var localStorageServiceMock = { get: jasmine.createSpy().and.returnValue(...) };

beforeEach(angular.mock.module(serviceModule, {
  localStorageService: localStorageServiceMock,
  appConfig: ...,
  locationStorageKey: ...
}));

幸运的是,我们有一个单独的类导出,带有ES6模块和default

import serviceModule, { IPMAService } from './IPMAService.service';

这使我们有机会在使用inject实例化服务之前在类原型方法上设置间谍:

beforeEach(() => {
 spyOn(IPMAService.prototype, '_getLocationsFromService').and.callThrough();
});
...
expect(service._getLocationsFromService).toHaveBeenCalled();

或者,可以在某些服务规范中模拟该方法,以提高粒度并专注于测试方法。

在构造函数中监视服务自己的方法并不是一件大事,但它增加了规范的强度。