Unit testing 为什么$provide仅在';angular.mock.module';功能,并且$q仅在';angular.mock.inject';功能?

Unit testing 为什么$provide仅在';angular.mock.module';功能,并且$q仅在';angular.mock.inject';功能?,unit-testing,angularjs,dependency-injection,jasmine,Unit Testing,Angularjs,Dependency Injection,Jasmine,我正在模拟AngularJS单元测试的服务。我正在使用$provide服务将“真实”服务替换为模拟服务(其中一个可用): 这个很好用。但是,我不喜欢使用angular.mock.module函数仅仅是为了引用$provide服务,然后在下面的angular.mock.inject函数中使用该服务。但是如果我直接将$provide作为参数添加到angular.mock.inject函数中,则会出现“未知提供程序”错误 我突然想到,我可以将所有模拟代码放在angular.mock.module函数中

我正在模拟AngularJS单元测试的服务。我正在使用
$provide
服务将“真实”服务替换为模拟服务(其中一个可用):

这个很好用。但是,我不喜欢使用
angular.mock.module
函数仅仅是为了引用
$provide
服务,然后在下面的
angular.mock.inject
函数中使用该服务。但是如果我直接将
$provide
作为参数添加到
angular.mock.inject
函数中,则会出现“未知提供程序”错误

我突然想到,我可以将所有模拟代码放在
angular.mock.module
函数中。但是,
$q
引用也有类似的问题,我需要它,因为我的模拟服务必须返回一个承诺

换句话说,如果我在
angular.mock.module
函数中添加
$q
参数,那么我也会得到一个“未知提供程序”错误


有没有办法简化这一点?很明显,我的方法很有效,但不知怎么的,我感觉不太对劲。我觉得我不理解为什么一些提供程序在
inject
函数中可用,而其他提供程序在
模块
函数中可用。

您不能在
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(...);
});

这是一个主要用于说明上述内容的示例。

当我不得不包装一个使用
$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

这非常好,而且很有效。。。只要你不使用承诺。这是一个plunk,展示了我的原始示例:这是一个用您建议的技术更新的fork:模拟服务没有被分配;看起来好像有什么东西干扰了时间安排。@Holf你可以用一个承诺,但你需要先把事情转一转。请查看此更新内容。@Holf您无法在
模块
函数中获得
$q
服务的实例,因为Angular没有向其中注入任何服务。正确的方法是使用
inject
功能。据我所知,这是设计的。@futuoad
angular.module
用于定义模块,而
angular.mock.module
用于将现有模块加载到内存中,以便测试可以访问其内容(服务、工厂、指令等)<代码>模拟。模块还用于配置注入器,以便您可以为任何可注入服务提供模拟对象。有关详细信息,请参阅。@FutuoAD
module
angular.mock.module
的全局别名,如文档中所述:
此函数也发布在窗口上,以便于访问。
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 */ });