2013-04-06 5 views
40

私はParseServiceを持っていますが、それを使用しているすべてのコントローラをテストするために模擬したいのですが、私はジャスミンスパイについて読んできました。誰でも私にカスタムサービスを模擬してコントローラテストで使用する方法の例を教えてもらえますか?コントローラをテストするためにサービスをモックする

は今、私は本を挿入するためにサービスを使用してコントローラーを持っている:

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"; 
       $location.path('/main'); 
      } 
      else { 
       $scope.registerResult = "Fail!"; 
       //$location.path('/'); 
      } 

     }); 
    }; 
}); 

サービスは、このようなものです:

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()); 
       newAcl.setPublicReadAccess(true); 
       book.setACL(newAcl); 

       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; 
    }); 

そして、私のテストでは、これまでのようになります。

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

    // // load the controller's module 
    beforeEach(module('BookCrossingApp')); 


    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"); 
     scope.registerNewBook(book); 
     //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 
     expect(mockService.registerBook).toHaveBeenCalled(); 
    }); 
    it('Dummy test', function() { 
     expect(true).toBe(true); 
    }); 
}); 

今すぐテストが失敗しています:

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

私は間違っていますか?

答えて

60

私が間違ってやっていたbeforeEachでコントローラに嘲笑サービスを注入されていません:あなたはこのようspyOn.and.returnValueを()あなたのサービスを注入してから使用することができます

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

    var scope; 
    var ParseServiceMock; 
    var AddBookCtrl; 

    // load the controller's module 
    beforeEach(module('BookCrossingApp')); 

    // 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(); 
     scope.registerNewBook(book); 

     expect(ParseServiceMock.registerBook).toHaveBeenCalled(); 
     //expect(ParseServiceMock.getBookRegistrationId).toHaveBeenCalled(); 
    }); 
}); 
-2

あなたのプロジェクトにangular-mocks.jsを含めて、following linkをよく読んでください。

+1

問題は解析サービスは、HTTP呼び出しをカプセル化するということですので、私は、D私のアプリでhttpBackendモックを使用する方法を見ていないのでしょうか、多分私はここでポイントを逃していると私はいつもこの種のサービスをテストするためにhttpBackendを使用しなければなりません。 –

+1

あなたのアプローチは良いと思います。 httpBackendは、コントローラをテストするのではなく、ParseServiceをテストするために使用する必要があります。あなたがhttpからhttpへの呼び出しをモックした場合、あなたはカプセル化に違反しています。統合テストを追加して、外部サーバーへの実際の呼び出しをテストできます。 –

11

beforeEach(angular.mock.module('yourModule')); 

beforeEach(angular.mock.inject(function($rootScope, $controller, ParseService) { 
    mock = { 
     $scope: $rootScope.$new(), 
     ParseService: ParseService 
    }; 
    $controller('AddBookCtrl', mock); 
})); 

it('should call Parse Service method', function() { 
    spyOn(mock.ParseService, "registerBook").and.returnValue({id: 3}); 

    mock.$scope.registerNewBook(); 

    expect(mock.ParseService.registerBook).toHaveBeenCalled(); 
}); 
1

次のJavitoのanswerに続いて、事実4年後。 Jasmineはスパイの真の方法を呼び出すために2.0の構文を変更しました。

変更:

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

へ:

spyOn(ParseServiceMock, 'registerBook').and.callThrough(); 

Source

関連する問題