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

时间:2013-10-10 13:34:56

标签: unit-testing angularjs dependency-injection jasmine

我正在嘲笑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引用有一个类似的问题,我需要这个引用,因为我的模拟服务必须返回一个promise。

换句话说,如果我向$q函数添加angular.mock.module参数,那么我也会收到“未知提供商”错误。

有没有办法简化这个?显然我的工作有点但不一定感觉不对。我觉得我不了解为什么某些提供商在inject个功能中可用,而其他提供商在module个功能中可用。

2 个答案:

答案 0 :(得分:55)

您不能在$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,主要说明了上述内容。

答案 1 :(得分:11)

当我不得不打包使用i >= NumberOfRows并且看起来很干净的服务时,这对我有用:

$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