web-dev-qa-db-ja.com

なぜ$ provideは 'angular.mock.module'関数でのみ使用でき、$ qは 'angular.mock.inject'関数でのみ使用できるのですか?

私は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関数で利用できる理由を理解していないように感じます。

39
Holf

前者は後者が使用するプロバイダーを登録するため、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 は、上記のほとんどを示しています。

55
Michael Benford

$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を使用することでした。

11
Claudiu