1

I have an angular 1.5 project with many modules and each module may depend on other modules. Trying to unit test say a controller which is part of a module I would do import the module like this:

angular.mock.module('SaidModule');

...then provide and inject its services where needed.

The problem is that SaidModule depends on AnotherModule1, AnotherModule2, AnotherModule3....

angular.module('SaidModule', ['AnotherModule1', 'AnotherModule2', 'AnotherModule3']);

So naturally when I call SaidModule the other modules are also invoked which is out of scope in terms of Unit testing

In the unit test I have tried the following solution

angular.module('AnotherModule1',[]);
angular.module('AnotherModule2',[]);
angular.module('AnotherModule3',[]);
angular.mock.module('SaidModule');

and although for the current unit test I have successfully decoupled the dependencies I have also destroyed the actual AnotherModule1, AnotherModule2, AnotherModule3 so when its there turn to be unit tested they are not even visible in the angular project which seems correct to me. as I am using angular.module to define a new module which just happens to override the actual module. This solution though is also suggested here mocking module dependencies

In the angular docs it states see angular docs mock module If an object literal is passed each key-value pair will be registered on the module via $provide.value, the key being the string name (or token) to associate with the value on the injector.

So it seems to me that the solution is using somehow angular.mock.module somehow to override the dependent modules but so far I have not found a solution. Any help much appreciated

isherwood
  • 58,414
  • 16
  • 114
  • 157
Leandros
  • 11
  • 2

1 Answers1

0

By calling angular.module('AnotherModule1',[]) you are redefining the AnotherModule1, which I think is causing your downstream problems. Instead, use $provide for each dependent service. There's no need to mock the dependent modules.

Let's say your controller definition looks like this:

angular
  .module('SaidModule', ['AnotherModule1', 'AnotherModule2'])
  .controller('SaidController', [
    '$scope', 
    'AnotherService', 
    function($scope, AnotherService) {
      this.anotherService = AnotherService.helper();
    }
  );

Then your test might look like:

describe('SaidController', function() {
  var controller, scope, AnotherService;

  beforeEach(module('SaidModule'));

  beforeEach(module(function($provide) {
    AnotherService = { helper: function() { return 0; } };
    $provide.value('AnotherService', AnotherService);
  }));

  beforeEach(inject(function($controller, $rootScope) {
    scope = $rootScope.$new();
    controller = $controller('SaidController', {
      $scope: scope
    });
  }));

  it('creates controller', function() {
    expect(controller).not.toBeNull();
  });
});

There's no need to mock the dependent modules, just the dependent services.

mikwat
  • 533
  • 3
  • 11
  • Although this is doesn't seem to work, I am not sure its the correct approach because when the module is run here beforeEach(angular.mock.module('SaidModule')); it will load its dependent modules and then I would be stubbing them or whatever afterwards. What I really want to do is stop them from being loaded when I call angular.mock.module phase somehow – Leandros Apr 28 '17 at 05:49
  • Maybe this post answers your question: http://stackoverflow.com/questions/17554727/mocking-angular-module-dependencies-in-jasmine-unit-tests#18228805 – mikwat Apr 28 '17 at 16:41
  • thanks for your reply @mikwat however I disagree with the aforementioned solution. The reason is that when you test a unit you should not care about what is happening in the outside world but in this case he is bringing in the module and in order to not run its code he is stubbing all its services and methods. And if you only have 1 module you are dependent on, it could be a temp solution but I have 5 dependant modules as the project is quite complex so its impossible/worthless for me to go and stub every single service the other modules are using – Leandros Apr 30 '17 at 11:21
  • I can't think of any way to avoid stubbing the dependent services and methods, in javascript or any other language for that matter. – mikwat Apr 30 '17 at 18:23
  • I think you have misunderstood my problem. Services and methods need to be stubbed I totally agree but the problem I am facing though is with module dependencies which I cant find a way to stub. E.g Module A has a dependency on Module B and C so when I instantiate module A in the unit test it will naturally run Module B and C as well. I believe the solution is using angular.mock.module somehow " If an object literal is passed each key-value pair will be registered on the module via $provide.value, the key being the string name (or token) to associate with the value on the injector." – Leandros May 07 '17 at 22:06
  • Ah, I think I understand now. Please see my updated solution. – mikwat May 08 '17 at 20:29