2013-01-07 11 views
19

Przeszedłem kilka tutoriali i podstawowych przykładów, ale mam problemy z pisaniem testów jednostkowych dla mojego kontrolera. Widziałem fragmenty kodu tworzące kontrolery i pozwalające na kątowe wstawianie obiektu $rootScope, który z kolei jest używany do tworzenia nowego obiektu scope dla kontrolera. Ale nie mogę zrozumieć, dlaczego ctrl.$scope? jest niezdefiniowana:

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

skończyło się używając scope zmienną zamiast ctrl.$scope ale na moim pierwszym teście nie mogłem dowiedzieć się, jak testować zmienną funkcji wewnątrz mojego kontrolera jednostka:

Kontroler:

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

Złamane jednostka Test:

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

To co mam

TypeError: Object # has no method 'searchMatch'

Jak można przetestować tę funkcję? W celu obejścia tego problemu przeniosłem moją metodę do zakresu $, aby móc przetestować pod kątem scope.searchMatch, ale zastanawiałem się, czy to jedyny sposób.

Wreszcie, na moich testach pojawia się $filterjest również niezdefiniowany, jak to wstrzyknąć? Próbowałem to, ale nie działa:

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

Dzięki

Aktualizacja: Sposób wspomniano powyżej, aby wstrzyknąć $ filtr działa dobrze.

+0

Mój test jaśminowy przełamuje metodę iniekcji. Nie znaleziono. Czego mi brakuje. kątowa nie jest pusta. Mam test, który przechodzi, który sprawdza, czy jest załadowany. – Hcabnettek

Odpowiedz

40

Moje zrozumienie jest, że w angularjs, należy przekazać obiekt zakresie do kontrolera, gdy aplikacja jest uruchamianie i kontroler zmodyfikować zakres. Sterownik nie jest już wywoływany.

To, co kontroler naprawdę robi, w Angularjs, inicjalizuje zasięg: kontroler działa tylko jeden raz. Jeśli to zrozumieć, uświadomić sobie, że z prośbą do sterownika do zakresu takiego:

currentScope = myController.scope; 

nie ma sensu.

(Nawiasem mówiąc, jedną z rzeczy, których nie lubię w Angular, są imiona, które wybrały.) Jeśli to, co robi kontroler, to inicjowanie zakresu, to nie jest to kontroler. to w interfejsie API).

Myślę, że „właściwy” sposób na testowanie „kontroler” tworzy nowy pusty zakres od podstaw w Jasmine beforeEach klauzuli i przy użyciu „kontroler” do inicjowanie nowy pusty zakres takiego: :

var ctrl, myScope; 

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

A potem testowanie nowego utworzonego zakres ma oczekiwanych właściwości:

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

innymi słowy, nie przetestować kontroler; testujesz zakres utworzony przez kontroler.

Robisz to dobrze.

+0

To ma więcej sensu. Wielkie dzięki ! – Ulises

1

Istnieją tylko dwie możliwości:

Dodaj searchMatch do zakresu (jak wspomniano) lub

zwróci searchMatch funkcyjne:

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

Jeśli to naprawdę musi pozostać prywatne, wtedy Będą musieli przetestować funkcje, które z niego korzystają.

Aby uzyskać $filter, można spróbować wykonać następujące czynności:

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

Dzięki, i jak wstawić filtr $? – Ulises

+0

Zaktualizowałem swoją odpowiedź. Wypróbuj funkcję angle-injector(), która zwraca obiekt $ injector, który zawiera usługi kątowe, takie jak filtr $, kontroler $, ... – asgoth

3

Oto inny wzór, który może być prostsze do naśladowania:

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

Można użyć tego samego wzorca, aby ustawić wartości dla $ i $ położenia okna, jak również innych.

Powiązane problemy