私はAngularJSユニットテストのサービスをモックアウトしています。 _$provide
_サービスを使用して、「実際の」サービスをモックアウトされたサービスに置き換えています(これは 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
_関数に入れることができると思います。しかし、その後、_$q
_参照で同様の問題が発生します。これは、モックされたサービスが約束を返す必要があるために必要です。
つまり、_$q
_パラメーターを_angular.mock.module
_関数に追加すると、「不明なプロバイダー」エラーも発生します。
これを簡素化する方法はありますか?明らかに私が持っているものは動作しますが、どういうわけか、それはまったく正しいとは感じません。一部のプロバイダがinject
関数で利用できる理由と、他のプロバイダがmodule
関数で利用できる理由を理解していないように感じます。
前者は後者が使用するプロバイダーを登録するため、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 は、上記のほとんどを示しています。
$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
を使用することでした。