为什么$只在'angular.mock.module'函数中可用,$ q只在'angular.mock.inject'函数中可用?

我正在嘲笑一个AngularJSunit testing的服务。 我正在使用$provide服务来replace模拟出来的“真实”服务(这是一个可用的plunker脚本 ):

 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代码放在angular.mock.module函数中。 但是,我也有类似的问题与$q参考,我需要嘲笑的服务必须返回一个承诺。

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

有没有办法简化这个? 很明显,我有作品,但不知何故,感觉不太对。 我觉得我不了解为什么有些提供程序可用于injectfunction,而其他提供modulefunction。

inject函数中不能使用$provide ,因为前者为后者提供注册提供者。 看一看:

 describe('...', function() { beforeEach(function() { module(function($provide) { $provide.constant('someValue', 'foobar'); }); inject(function(someValue) { var value = someValue; // will be 'foobar'; }); }); }); 

你可以这样写你的testing:

 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脚本主要说明上述。

当我必须包装一个使用$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