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