2013-01-07 96 views
19

我已經通過了一些教程和基本示例,但是我很難爲我的控制器編寫單元測試。我見過代碼片段實例化控制器,並讓角度注入對象,而對象又用於爲控制器創建一個新的對象scope。但我想不通爲什麼ctrl.$scope未定義

describe('EmployeeCtrl', function() { 
    var scope, ctrl, $httpBackend; 

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, $filter) { 
     $httpBackend = _$httpBackend_;  

     scope = $rootScope.$new(); 
     ctrl = $controller('EmployeeCtrl', { $scope: scope}); 
     expect(ctrl).not.toBeUndefined(); 
     expect(scope).not.toBeUndefined(); //<-- PASS!  
     expect(ctrl.$scope).not.toBeUndefined(); //<-- FAIL!  
    })); 
}); 

我結束了使用scope變量而不是ctrl.$scope但當時我的第一次測試中,我無法弄清楚如何單元測試函數變量我的控制器內:

控制器:

function EmployeeCtrl($scope, $http, $filter, Employee) { 
    var searchMatch = function (haystack, needle) { 
    return false; 
    } 
} 

破碎部測試:

it('should search ', function() {     
    expect(ctrl.searchMatch('numbers','one')).toBe(false); 
}); 

這是我得到

TypeError: Object # has no method 'searchMatch'

你怎麼測試功能?作爲一種解決方法,我將我的方法移至$ scope,所以我可以測試scope.searchMatch,但我想知道這是否唯一方法。

最後,在我的測試中出現$filter也未定義,你怎麼注入它?我試過,但沒有奏效:

ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter }); 

感謝

更新: 上述注入$過濾器的方法工作得很好。

+0

我的茉莉花測試打破了注射法。它沒有被發現。我錯過了什麼。角度不爲空。我有一個測試通過驗證它的加載。 – Hcabnettek

回答

40

我的理解是,在Angularjs,你傳遞一個範圍對象控制器當應用程序啓動和控制修改的範圍。控制器不再被調用。

在Angularjs中,一個控制器真的在做什麼:初始化範圍:控制器只運行一次。 如果你明白這一點,你就會意識到,問到控制器爲這樣的範圍:

currentScope = myController.scope; 

不有道理。 (順便說一句,我不喜歡Angular中的一個東西是他們選擇的名稱,如果'控制器'正在做的是初始化範圍,那麼它並不是一個真正的控制器。這在Angular API中)。

我認爲測試「控制器」的「正確」的方式是從頭開始創建的茉莉花beforeEach第一個新的空白範圍,並使用「控制器」爲初始化一個新的空白範圍如下: :

var ctrl, myScope; 

beforeEach(inject(function($controller, $rootScope) { 
    myScope = $rootScope.$new(); 
    ctrl = $controller('myController', { 
     $scope: myScope 
    }); 
})); 

,然後測試新創建範圍具有預期性能:

it('In the scope, the initial value for a=2', function() { 
      expect(myScope.a).toBe(2); 
}); 

換句話說,你不測試控制器;您測試控制器創建的範圍。

所以,你做對了。

+0

這樣做更有意義。非常感謝 ! – Ulises

1

只有兩種可能:

添加searchMatch的範圍(如你所提到的)或

返回的searchMatch功能:

function EmployeeCtrl($scope, $http, $filter, Employee) { 
    return { 
    searchMatch: function (haystack, needle) { 
     return false; 
    } 
    }; 
} 

如果真的必須保持私有,那麼你必須測試使用它的功能。

要獲得$filter,你可以嘗試以下方法:

var $filter = angular.injector(['ng']).get('$filter'); 
+0

謝謝,我該如何注入$ filter? – Ulises

+0

我已經更新了我的答案。嘗試使用angular.injector(),它返回一個$ injector對象,其中包含角度服務,如$ filter,$ controller,... – asgoth

3

這裏是另一種模式,可能是簡單的遵循:

var $scope; 
beforeEach(module(function ($provide) { 
    $scope = { 
    // set anything you want here or nothing 
    }; 
    $provide.value('$scope', $scope); 
})); 

var ctrl; 
beforeEach(inject(function ($controller) { 
    ctrl = $controller('MyController'); 
})); 

it('should test something...', function() { 
    // $scope will have any properties set by 
    // the controller so you can now do asserts 
    // on them. 
}); 

您可以使用此相同的模式設置爲$位置和$窗口以及其他值。

相關問題