2017-10-08 117 views
0

在我的角JS應用程序中,我有一個mainController,它將userFactory作爲參數。 userFactory由一個名爲userService的對象組成,該對象又具有一個userDetails對象和一些包括resetUserDetails的方法。 (詳見下頁)使用Jasmine spyOn在工廠中定義的對象的方法

在mainController中我有一個logOut函數,它調用userFactory.userService.resetUserDetails方法。我想用茉莉花測試這個logOut函數,但是我收到了一些錯誤。我對茉莉花很陌生,所以很抱歉,如果它的東西明顯我失蹤了。

所以首先在我的Jasmine套件中創建一個MainControllerSpec來測試我的mainController。

在這個規範中,我注入了一個名爲userFactory的工廠。我想我的spyOn方法resetUserDetails如下但得到一個錯誤:

spyOn(userFactory, 'userService.resetUserDetails'); 

錯誤:userService.resetUserDetails()不存在。

我想這個過程通過創建我的userFactory一個函數調用測試(userService對象之外)和它的作品以及至少我知道在規範的工廠注入設置了罰款。
任何幫助非常感謝。在mainController謝謝

MainControllerSpec.js

describe("MainController", function() { 
    beforeEach(angular.mock.module('mapModule', 'ngRoute','ngTouch', 'ngAnimate')); 
    var scope, userFactory; 

    beforeEach(inject(function($rootScope, $controller, _userFactory_){ 
     scope = $rootScope.$new(); 
     userFactory = _userFactory_; 
     $controller('mainController', { 
      $scope: scope 
     }); 
    })); 


    describe('The logOut function', function() { 
     it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() { 
      //spyOn takes in a factory and a method of that factory 
      spyOn(userFactory, 'userService.resetUserDetails'); 
      //spyOn(userFactory, 'test'); tried this and it works. 
      scope.logOut(); 
      expect(userFactory.userService.resetUserDetails).toHaveBeenCalled(); 
     }); 
    }); 

}); 

註銷功能
$scope.logOut = function(){ 
     userFactory.userService.resetUserDetails(); 
     //userFactory.test(); //tried this with spyOn in jasmine 
    } 

userFactory

mapApp.factory('userFactory', function(){ 

    var userService = { 
     /* 
     * Initialize a userDetails object. 
     */ 
     userDetails : { 
      "userID" : null, 
      "facebookUserID" : "", 
      "facebookName" : "", 
      "facebookProfilePic" : "", 
      "userPrivilegeID" : 1, 
      "userToken" : "", 
      "isLoggedIn" : false 
     }, 
     resetUserDetails : function(){ 
      /* 
      * This method resets the userDetails object. 
      */ 
      this.userDetails = { 
       "userID" : null, 
       "facebookUserID" : "", 
       "facebookName" : "", 
       "facebookProfilePic" : "", 
       "userPrivilegeID" : 1, 
       "userToken" : "", 
       "isLoggedIn" : false 
      }; 
     } 
    }; 
    var test = function(){ 
     /* 
     * for testing spyOn in Jasmine 
     */ 
    }; 
    //return public API so that we can access it in all controllers 
    return{ 
     userService: userService, 
     test: test 
    }; 
}); 
+0

我剛copped它。道歉。以下工作正常。 spyOn(userFactory.userService,'resetUserDetails'); .. – Sarah

+0

通常你可能想要完全在控制器測試中模擬服務,而不是一個一個的監視它的方法。例如。 https://stackoverflow.com/a/46595428/3731501 – estus

+0

@estus好的謝謝你的建議。我會檢查出 – Sarah

回答

1

你需要模擬你userFactory之前直接注入它。 單元測試的目標是將文件測試爲黑盒子,而不直接測試相關方法的邏輯。

對於他們而言,您將編寫userFactory的規格文件。

在這種情況下,你可以做的是類似如下:

describe("MainController", function() { 
 

 
    beforeEach(angular.mock.module('mapModule', 'ngRoute', 'ngTouch', 'ngAnimate')); 
 
    var scope, userFactory; 
 

 
    // here mock the methods of your factory 
 
    beforeEach(module(function($provide) { 
 
    $provide.value('userFactory', { 
 
     myFirstObject: { 
 
     myFirstMethod: function() {} 
 
     } 
 
    }); 
 
    })); 
 

 
    beforeEach(inject(function($rootScope, $controller, _userFactory_) { 
 
    scope = $rootScope.$new(); 
 
    userFactory = _userFactory_; 
 
    $controller('mainController', { 
 
     $scope: scope 
 
    }); 
 
    })); 
 

 

 
    describe('The logOut function', function() { 
 
    it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() { 
 
     //here spy on the method and return what you would like to return in this test 
 
     // or if you don't need to manage the return, as it seems you don't, just use callThrough 
 
     spyOn(userFactory.myFirstObject, 'myFirstMethod').and.callThrough(); 
 
     scope.logOut(); 
 
     expect(userFactory.myFirstObject.myFirstMethod).toHaveBeenCalled(); 
 
    }); 
 
    }); 
 

 
});

+0

謝謝。我明天會試一試。儘管我在上面的評論中看到了自己的代碼,我需要這樣說:spyOn(userFactory.userService,'resetUserDetails');而不是:spyOn(userFactory,'userService.resetUserDetails'); ..(因爲我的方法是在userFactory內的一個名爲userService的對象內)..但我感謝你的建議,並會嘗試你的建議。謝謝 – Sarah

+0

哦對不起,沒有注意到你的方法是在嵌套對象裏面,更改了代碼 – quirimmo

+0

謝謝你。我試過這個,很好,謝謝。但是我做了一件額外的事情(感謝評論中的另一個人)。我使用jasmine.createSpy()創建了一個間諜,因此$ provide.value('userFactory',{ myFirstObject:{ myFirstMethod:jasmine.createSpy() } });然後我並不需要在套件的測試中使用spyOn,而是繼續使用其餘的代碼。無論如何,你的回答對我的問題是正確的,所以我現在就接受它。非常感謝你 – Sarah