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

Hol*_*olf 39 unit-testing dependency-injection jasmine angularjs

我正在嘲笑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);
    });
});
Run Code Online (Sandbox Code Playgroud)

这很好用.但是,我不喜欢这样一个事实,即我只使用一个angular.mock.module函数来提供对$provide服务的引用,然后在angular.mock.inject下面的函数中使用该服务.但是,如果我直接将其$provide作为参数添加到angular.mock.inject函数中,则会出现"未知提供程序"错误.

在我看来,我可以将所有模拟代码放在angular.mock.module函数中.但是我在$q引用时遇到了类似的问题,因为我的模拟服务必须返回一个promise.

换句话说,如果我$qangular.mock.module函数添加一个参数,那么我也会得到一个"未知提供者"错误.

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

Mic*_*ord 55

您不能$provideinject函数中使用,因为前者注册后者使用的提供程序.看一看:

describe('...', function() {
    beforeEach(function() {
        module(function($provide) {
            $provide.constant('someValue', 'foobar');
        });

        inject(function(someValue) {
            var value = someValue; // will be 'foobar';
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

你可以用这种方式编写测试:

describe('...', function() {
    var serviceMock;

    beforeEach(function() {
        serviceMock = {
           someMethod: function() { ... }
        };

        module(function($provide) {
            $provide.value('service', serviceMock);
        });

        inject(function(service) {
            ...                         
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

事实上,在使用以下方法注入之前,您甚至不需要实现模拟服务$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(...);
});
Run Code Online (Sandbox Code Playgroud)

这是一个Plunker脚本,主要说明了上述内容.

  • @Holf你可以使用一个承诺,但你需要先把事情移动一下.查看此更新的[Plunker脚本](http://plnkr.co/edit/Fi1SQq). (7认同)
  • @FutuToad`module`是`angular.mock.module`的全局别名,如文档中所述:`此函数也发布在窗口上以便于访问. (3认同)
  • @FutuToad`angular.module`用于定义模块,而angular.mock.module用于将现有模块加载到内存中,因此测试可以访问其内容(服务,工厂,指令等).`mock.module`也用于配置注入器,因此您可以为任何可注入服务提供模拟对象.有关更多信息,请查看[Angular docs](http://docs.angularjs.org/api/angular.mock.module). (2认同)

Cla*_*diu 11

当我必须包装一个使用过$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 */ });
Run Code Online (Sandbox Code Playgroud)

诀窍是使用$provide.factory而不是$provide.value.