Angular,测试自定义提供程序和配置

时间:2015-03-18 14:31:14

标签: javascript angularjs unit-testing

我有一个提供程序,它使用构造函数获取其中设置的项目,然后返回带有一些函数的$ get以供使用。问题是$ get函数都使用了我用构造函数设置的对象。我希望能够设置构造函数进行测试(或者可能采用不同的方法?)。这就是我所拥有的。

提供者(为requirejs构建)

  function URLprovider(angular, URLfactory, underscore) {
     var metadata = {
         componentName: 'URLprovider',
         moduleName: 'test.URLprovider'
     };

     $moduleObjectProvider.$inject = [];

     function $moduleObjectProvider() {

         var currentModules = {};

         function modulePush(currentModule, name) {
                 var tempMod = {};
                 tempMod[name] = currentModule;
                 _.extend(currentModules, tempMod);
             }

        //constructor
         this.moduleConstructor = function(name, cb) {
             if (!currentModules[name]) {
                 this.states = [];
                 this.callback = cb;
                 modulePush(this, name);
             }
         };

         this.$get = $get;

         $get.$inject = ['URLfactory', '$log', '$location'];

         function $get(URLfactory, $log, $location) {

             return {
                 go: function(name, stateName, options) {

                 },
                 prep: function(name, stateName, options) {

                 },
                 modules: function() {
                     return currentModules;
                 }
             };
         }
     }

     angular.module(metadata.moduleName, []).provider(metadata.componentName, $moduleObjectProvider);

所以 - 我要测试的函数在$ get中。如果我在测试中使用console.log URLprovider,我只能获取get中的函数。每个get函数都使用使用构造函数设置的currentModules变量。因此,在正常情况下,我只需在配置中设置它,例如 -

  .config(function(URLproviderProvider) {
                 var callback = function(name, obj) {
            console.log(name, obj);
        }

        var mod = new URLproviderProvider.moduleConstructor("module1,", callback)
            .addState("calender", ["day", "week", "month"]);


    })

这样就可以将该对象推送到currentModules中。我需要这样做才能进行基本的测试,因为$ get中的所有函数都不会在currentModules中没有内容的情况下正确运行。

所以我想知道的是 -

有没有办法在测试时伪造变量currentModules?

有没有办法模拟配置来设置currentModules(在beforeEach中)进行测试,我觉得我需要以不同的方式公开构造函数(我现在不确定),因为当我登录时在测试中提供URLprovider,它只返回$ get中的函数,我不认为我在那里有访问权限吗?

或者我应该以另一种方式处理这个问题?

我正在使用Karma,Chai和Sinon。谢谢!

凹凸!

编辑:

所以我尝试通过将构造函数放入$ get - like

来将构造函数暴露给测试
     moduleConstructor: function(name, cb) {
         if (!currentModules[name]) {
             this.states = [];
             this.callback = cb;
             modulePush(this, name);
         }
     };

然而,在get中,这个引用现在已经关闭了(我们在这里。$ get)。如果我可以公开构造函数,我可以调用它来推送一个新的并通过它进行测试。如果我尝试在get中的函数内部记录它,则引用整个get。

因此,在外面有一个this.moduleConstructor函数可以让我调用一个新的关于我希望它如何行动的内容。

编辑:凹凸!仍然无法想出这一个:(

1 个答案:

答案 0 :(得分:1)

我在帖子How to test AngularJS custom provider中找到了一个非常好的答案,特别是Stephane Catala(4月22日)给出的一个通用函数providerGetter的答案,它允许您在Jasmine测试中访问提供者。您还可以访问提供商提供的服务。使用该功能(在Jasmine中)你可以这样做:

describe("provider test", function() {
  var infoProvider, info;

  function providerGetter(moduleName, providerName) {
    var provider;
    module(moduleName, 
       [providerName, function(Provider) { provider = Provider; }]);
    return function() { inject(); return provider; }; 
  }

  beforeEach(function() {
    infoProvider = providerGetter('test', 'infoProvider')();
  });

  it('should return nothing if not set', function() {
    inject(function(_info_) { info = _info_; });
    expect(info.getInfo()).toEqual('nothing');
  });

  it('should return the info that was set', function() {
    infoProvider.setInfo('something');
    inject(function(_info_) { info = _info_; });
    expect(info.getInfo()).toEqual('something');
  });
});

此测试的提供者非常简单

    angular
        .module('test', [])
        .provider('info', info);

    function info() {
        var nfo = 'nothing';
        this.setInfo = function(s) { nfo = s; };
        this.$get = Info;

        function Info() {
            return { getInfo: function() {return nfo;} };
        }
    }

不完全确定如何转换为sinon,但providerGetter(使用angular-mocks函数)应该有效。