Craig Warren
Craig Warren

Reputation: 1665

How to unit test a multi module angular product

I've got an angular project which contains multiple modules which are used to separate the logic of the project. Obviously plenty of these modules have dependencies on other modules defined within the project.

As an example I have a module called 'myapp.shared.mixpanel' which contains a service called mixpanelService for sending tracking events. There is another module called 'myapp.feature' which has a dependency on 'myapp.shared.mixpanel' so that it can access the mixpanelService.

angular.module('myapp.feature', ['myapp.shared.mixpanel']);

When I test a controller inside the 'myapp.feature' module I load the module:

angular.mock.module('myapp.feature');

but this has a dependency on 'myapp.shared.mixpanel'.

Is there a way to prevent the "real" version of this module from being loaded as a dependency and instead load an "empty" version of the dependent modules which I can add mock services/controllers/etc to later?

Upvotes: 1

Views: 2269

Answers (2)

user1364910
user1364910

Reputation:

Use the $provide override method.

As an example I have a module called 'myapp.shared.mixpanel' which contains a service called mixpanelService for sending tracking events. There is another module called 'myapp.feature' which has a dependency on 'myapp.shared.mixpanel' so that it can access the mixpanelService.

In your controller test (the controller in myapp.feature) you would do the following:

var $scope, mixPanelService;

beforeEach(function () {
  mixPanelService = {};

  module('myapp.feature', function ($provide) {
    // Here we are $providing a value of the same name to our current module. This is equivalent to the module.config method.
    $provide.value('mixPanelService', mixPanelService);
  });

  inject(function ($controller, $injector) {
    $scope = $injector.get('$rootScope').$new();
    mixPanelService = $injector.get('mixPanelService');       

    $controller('yourController', {
      $scope: $scope
      mixPanelService: mixPanelService
    });
  });

  // Add the required methods to mixPanelService (here I'm using sinon.stub())

  mixPanelService.someMethodMyControllerIsUsing = sinon.stub();
});

Now you don't have to worry about broken dependencies, nor do you have to worry about implementation details that should be tested in another isolated unit test.

mixPanelService is stubbed out and available in your module, and you didn't have to instantiate the .shared.mixpanel in a spec suite that has nothing to do with it.

Upvotes: 1

Michael Radionov
Michael Radionov

Reputation: 13309

In Angular you can override a previously registered module with the same name (see Creation versus Retrieval). So basically you can override your dependency-module with empty one in your test:

angular.module('myapp.shared.mixpanel', []);
angular.mock.module('myapp.feature'); 

Upvotes: 0

Related Questions