Javito Hertfy Javito Hertfy - 2 months ago 6x
AngularJS Question

Mock a service in order to test a controller

I have a ParseService, that I would like to mock in order test all the controllers that are using it, I have been reading about jasmine spies but it is still unclear for me. Could anybody give me an example of how to mock a custom service and use it in the Controller test?

Right now I have a Controller that uses a Service to insert a book:

BookCrossingApp.controller('AddBookCtrl', function ($scope, DataService, $location) {

$scope.registerNewBook = function (book) {
DataService.registerBook(book, function (isResult, result) {

$scope.$apply(function () {
$scope.registerResult = isResult ? "Success" : result;
if (isResult) {
//$scope.registerResult = "Success";
else {
$scope.registerResult = "Fail!";


The service is like this:

angular.module('DataServices', [])

* Parse Service
* Use Parse.com as a back-end for the application.
.factory('ParseService', function () {
var ParseService = {
name: "Parse",

registerBook: function registerBook(bookk, callback) {

var book = new Book();

book.set("title", bookk.title);
book.set("description", bookk.Description);
book.set("registrationId", bookk.RegistrationId);
var newAcl = new Parse.ACL(Parse.User.current());

book.save(null, {
success: function (book) {
// The object was saved successfully.
callback(true, null);
error: function (book, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
callback(false, error);

return ParseService;

And my test so far look like this:

describe('Controller: AddBookCtrl', function() {

// // load the controller's module

var AddBookCtrl, scope, book;

// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope;
book = {title: "fooTitle13"};
AddBookCtrl = $controller('AddBookCtrl', {
$scope: scope

it('should call Parse Service method', function () {

//We need to get the injector from angular
var $injector = angular.injector([ 'DataServices' ]);
//We get the service from the injector that we have called
var mockService = $injector.get( 'ParseService' );
mockService.registerBook = jasmine.createSpy("registerBook");
//With this call we SPY the method registerBook of our mockservice
//we have to make sure that the register book have been called after the call of our Controller
it('Dummy test', function () {

Right now the test is failing:

Expected spy registerBook to have been called.
Error: Expected spy registerBook to have been called.

What I am doing wrong?


What I was doing wrong is not injecting the Mocked Service into the controller in the beforeEach:

describe('Controller: AddBookCtrl', function() {

    var scope;
    var ParseServiceMock;
    var AddBookCtrl;

    // load the controller's module

    // define the mock Parse service
    beforeEach(function() {
        ParseServiceMock = {
            registerBook: function(book) {},
            getBookRegistrationId: function() {}

   // inject the required services and instantiate the controller
   beforeEach(inject(function($rootScope, $controller) {
       scope = $rootScope.$new();
       AddBookCtrl = $controller('AddBookCtrl', {
           $scope: scope,
           DataService: ParseServiceMock

   it('should call registerBook Parse Service method', function () {
       var book = {title: "fooTitle"}

       spyOn(ParseServiceMock, 'registerBook').andCallThrough();
       //spyOn(ParseServiceMock, 'getBookRegistrationId').andCallThrough();