AngularJS + Karma: reuse a mock service when unit testing directives or controllers AngularJS + Karma: reuse a mock service when unit testing directives or controllers angularjs angularjs

AngularJS + Karma: reuse a mock service when unit testing directives or controllers


Instead of spraying the testing code with spies you can create a proper mock of the service in its own module and add it in any test that needs it.

The controller unit test sits in a test/spec/modules/user/controller.js file.

The mocked service sits in a test/mock/modules/user/service.js file.

For a controller method:

$scope.refreshList = function() {  UserService.all(pageNumber, size, sort, function(data) {    $scope.users = data.content;    $scope.page = data.page;  });};

the mocked service:

(function () {'use strict';angular.module('app.user.mock', ['app.user']);angular.module('app.user.mock').factory('UserServiceMock',  ['$q',  function($q) {    var factory = {};    factory.mockedUsers = {       content: [ { firstname: 'Spirou', lastname: 'Fantasio', email: 'spirou@yahoo.se', workPhone: '983743464365' } ],      page: '1'    };    factory.search = function(searchTerm, page, size, sort, callback) {      var defer = $q.defer();      defer.resolve(this.mockedUsers);      defer.promise.then(callback);      return defer.promise;    };    factory.all = function(page, size, sort, callback) {      var defer = $q.defer();      defer.resolve(this.mockedUsers);      defer.promise.then(callback);      return defer.promise;    };    return factory;  }]);})();

and the controller unit test:

(function () {'use strict';var $scope;var listController;var UserServiceMock;beforeEach(function() {  module('app.project');  module('app.user.mock'); // (1)});beforeEach(inject(function($rootScope, _UserServiceMock_) {  $scope = $rootScope.$new();  UserServiceMock = _UserServiceMock_; // (2)}));describe('user.listCtrl', function() {  beforeEach(inject(function($controller) {    listController = $controller('user.listCtrl', {      $scope: $scope,      UserService: UserServiceMock    });  }));  it('should have a search function', function () { // (3)    expect(angular.isFunction(UserServiceMock.search)).toBe(true);  });  it('should have an all function', function () {    expect(angular.isFunction(UserServiceMock.all)).toBe(true);  });  it('should have mocked users in the service', function () {    expect(UserServiceMock.mockedUsers).toBeDefined();  });  it('should set the list of users in the scope', function (){    expect($scope.users).not.toEqual(UserServiceMock.mockedUsers);    $scope.refreshList();    $scope.$digest();    expect($scope.users).toEqual(UserServiceMock.mockedUsers.content);  });});})();

You add the app.user.mock module containing the mocked service (1) and inject the mocked service in the controller (2).

You can then test your mocked service has been injected (3).


I created a .js file that just contained a plain old javascript function that I called to create the mock. Another plain old javascript function to configure the server responses for tests. And like you say, if you define a global variable with the json responses then you can use that in your tests to compare against