2013-10-10 76 views
38

我正在嘲笑AngularJS单元测试的服务。我使用的是$provide服务与嘲笑了一个(这是可用plunker script),以取代“真实”服务:

describe('My Controller', function() { 

    var $scope; 
    var $provide; 

    beforeEach(angular.mock.module('myApp')); 

    beforeEach(angular.mock.module(function (_$provide_) { 

     $provide = _$provide_; 

    })); 

    beforeEach(angular.mock.inject(function($rootScope, $controller, $q){ 

     var mockMyService = { 
      getAll : function() { 
       var deferred = $q.defer(); 
       deferred.resolve([ 
      { itemText: "Foo" }, 
      { itemText: "Bar" } 
       ]); 

       return deferred.promise; 
      } 
     }; 

     $provide.value('myService', mockMyService); 

     $scope = $rootScope.$new(); 

     $controller('MyCtrl', { $scope: $scope }); 

     $rootScope.$apply(); 

    })); 

    it('Has two items defined', function() { 
     expect($scope.items.length).toEqual(2); 
    }); 
}); 

这一切正常。但是,我不喜欢我使用angular.mock.module函数仅仅提供$provide服务的事实,该服务随后在以下angular.mock.inject函数中使用。但是,如果直接将$provide作为参数添加到angular.mock.inject函数中,则会出现“未知提供者”错误。

在我看来,我可以把所有模拟代码放在angular.mock.module函数中。但后来我有一个类似的问题,$q参考,我需要我的模拟服务必须返回一个承诺。

换句话说,如果我将一个$q参数添加到angular.mock.module函数,那么我也会得到一个'unknown provider'错误。

有没有办法简化这个?很显然,我有些作品,但不知怎的,它感觉不太对劲。我觉得我对inject函数中为什么有些提供程序可用以及module函数中可用的其他提供程序不了解。

回答

53

您不能在inject函数中使用$provide,因为前者的注册提供程序供后者使用。请看:

describe('...', function() { 
    beforeEach(function() { 
     module(function($provide) { 
      $provide.constant('someValue', 'foobar'); 
     }); 

     inject(function(someValue) { 
      var value = someValue; // will be 'foobar'; 
     }); 
    }); 
}); 

你可以尽管编写测试是这样的:

describe('...', function() { 
    var serviceMock; 

    beforeEach(function() { 
     serviceMock = { 
      someMethod: function() { ... } 
     }; 

     module(function($provide) { 
      $provide.value('service', serviceMock); 
     }); 

     inject(function(service) { 
      ...       
     }); 
    }); 
}); 

事实上,你甚至不需要与$provide注射之前实现嘲笑服务:

beforeEach(function() { 
    serviceMock = {}; 

    module(function($provide) { 
     $provide.value('service', serviceMock); 
    }); 

    inject(function(service) { 
     ...       
    }); 
}); 

it('tests something', function() { 
    // Arrange 
    serviceMock.someMethod = function() { ... } 

    // Act 
    // does something 

    // Assert 
    expect(...).toBe(...); 
}); 

这里是一个Plunker script说明主要是上述。

+0

这是非常好的,它的工作原理...只要你不使用诺言。这里是一个显示我原来的例子plunk:http://plnkr.co/edit/1Gbr1N?p=preview 这里是一个叉你用建议的技术更新:http://plnkr.co/edit/ptAWcb?p =预览 模拟服务没有被分配;它看起来好像有些事情正在干扰时机。 – Holf

+0

我想知道为什么我无法从'模块'功能中获得'$ q'库?如果可以的话,那么我就有我需要的一切来在那里创建模拟服务。 – Holf

+7

@Holf您可以使用承诺,但您需要首先移动一些东西。看看这个更新的[Plunker脚本](http://plnkr.co/edit/Fi1SQq)。 –

11

这为我工作,当我不得不换用它和$q看起来挺干净的一个服务:

var _ServiceToTest_; 
beforeEach(function() { 
    module('module.being.tested'); 
    module(function ($provide) { 
     $provide.factory('ServiceToMock', function ($q, $rootScope) { 
      var service = ...; 
      // use $q et al to heart's content 
      return service; 
     }); 
    }); 
    inject(function (_ServiceToTest_) { 
     ServiceToTest = _ServiceToTest_; 
    }); 
}); 

it('...', function() { /* code using ServiceToTest */ }); 

诀窍是使用$provide.factory而不是$provide.value

相关问题