Почему $предоставляется только в функции angular.mock.module ', а $q доступно только в функции angular.mock.inject'?
Я издеваюсь над сервисом для AngularJS Unit Test. Я использую службу $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
, тогда я также получу ошибку "неизвестного провайдера".
Есть ли способ упростить это? Очевидно, что у меня есть работы, но это не совсем правильно. Я чувствую, что мне не хватает понимания того, почему некоторые поставщики доступны в inject
, а другие доступны в module
.
Ответы
Ответ 1
Вы не можете использовать $provide
в функции inject
, потому что прежний регистрирует поставщиков для использования последними. Посмотрите:
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, в основном иллюстрированный выше.
Ответ 2
Это сработало для меня, когда мне пришлось обернуть службу, которая использовала $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 content
return service;
});
});
inject(function (_ServiceToTest_) {
ServiceToTest = _ServiceToTest_;
});
});
it('...', function () { /* code using ServiceToTest */ });
Хитрость заключалась в использовании $provide.factory
вместо $provide.value
.