Why is $provide only available in the 'angular.mock.module' function, and $q only available in the 'angular.mock.inject' function? Why is $provide only available in the 'angular.mock.module' function, and $q only available in the 'angular.mock.inject' function? angularjs angularjs

Why is $provide only available in the 'angular.mock.module' function, and $q only available in the 'angular.mock.inject' function?


You can't use $provide within the inject function because the former registers providers for the latter to use. Take a look:

describe('...', function() {    beforeEach(function() {        module(function($provide) {            $provide.constant('someValue', 'foobar');        });        inject(function(someValue) {            var value = someValue; // will be 'foobar';        });    });});

You can though write your test this way:

describe('...', function() {    var serviceMock;    beforeEach(function() {        serviceMock = {           someMethod: function() { ... }        };        module(function($provide) {            $provide.value('service', serviceMock);        });        inject(function(service) {            ...                                 });    });});

In fact, you don't even need to implement the mocked service before injecting it with $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(...);});

Here's a Plunker script illustrating mostly of the above.


This worked for me when I had to wrap a service which used $q and seems quite clean:

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 */ });

The trick was to use $provide.factory instead of $provide.value.