2014-12-14 5 views
7

In meiner AngularJS-Anwendung habe ich Probleme, herauszufinden, wie der Einheitentest ausgeführt werden kann, wenn die Ausführung eines Versprechens eine location.url ändert. Ich habe eine Funktion, Login, die einen Service, AuthenticationService aufruft. Es gibt das Versprechen zurück, und die Ausführung des Versprechens ändert die location.url.AngularJS-Fehler: Unerwartete Anforderung (keine weiteren Anforderungen werden erwartet)

Dies ist der Controller AuthCtrl:

angular 
    .module('bloc1App') 
    .controller('AuthCtrl', ['$scope', '$http','$location', 'AuthenticationService', 
    function($scope, $http, $location, AuthenticationService) { 

    this.AuthenticationService = AuthenticationService; 
    var self = this; 

    $scope.login = function(username, password){ 
    self.AuthenticationService 
     .login(username, password) 
     .then(function(){ 
     $location.url('/tasks'); 
     }); 
    }; 
} 
]); 

Dies ist mein Versuch am Gerät zu testen:

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

     var scope, 
      location, 
      route, 
      q, 
      rootScope, 
      AuthCtrl; 

     beforeEach(module('bloc1App')); 

     beforeEach(inject(function($controller, $rootScope, $location, $route, $q) { 
     scope = $rootScope.$new(); 
     q = $q; 
     rootScope = $rootScope; 
     location = $location; 
     route = $route; 

     AuthCtrl = $controller('AuthCtrl', { 
     $scope: scope, 
     $route: route, 
     $location: location 
     }); 

    })); 

    it('login should redirect user to tasks view', function(){ 
     var deferred = q.defer(); 
     spyOn(AuthCtrl.AuthenticationService, 'login').andReturn(deferred.promise); 
     spyOn(location, 'url'); 
     scope.login('foo', 'foo'); 
     deferred.resolve(); 
     scope.$apply(); 
     expect(location.url).toHaveBeenCalledWith('/tasks'); 
    }); 
    }); 

Wenn ich diesen Test ausführen, bekomme ich diesen Fehler. Ich bekomme den gleichen Fehler, wenn ich rootScope verwenden $ apply() statt.

Error: Unexpected request: GET views/AuthView.html 
No more request expected 

Wenn ich Umfang nehmen $ apply(), ich diesen Fehler.

Expected spy url to have been called with [ '/tasks' ] but it was never called. 

Alle Ideen, wie um das zu beheben? Dies ist das erste Mal, dass ich ein Versprechen in der Einheit teste, und ich bin wahrscheinlich konzeptionell falsch verstanden, wie das geht.

Vielen Dank im Voraus für Ihre Hilfe.

Antwort

4

Wenn Sie mit AngularJS Unit-Testing durchführen, verwenden Sie anstelle von echten Services tatsächlich Mock-Services vom ngMock-Modul. In diesem Fall kommt Ihr Fehler wahrscheinlich von $httpBackend Mock, der zuerst "vorbereitet" werden muss, wenn Sie erwarten, dass die getesteten Einheiten $http verwenden, um echte Anforderungen zu senden. (Ich sehe Ihren Code nicht mit $http irgendwo, so dass ich denke, es gibt einen Teil, den Sie hier nicht zeigen.)

Grundsätzlich müssen Sie die $httpBackend Mock sagen, dass Sie eine bestimmte Anfrage erwarten $httpBackend.when (oder Sie können $httpBackend.expect verwenden, wenn Sie überprüfen möchten, ob die Anfrage tatsächlich aufgerufen wurde) und welche Antwort zurückgegeben werden soll.

Also, Ihr Fehler hat nichts mit Versprechungen und alles zu tun mit Testeinheiten, die mit dem Server verbinden zu tun.

+0

Vielen Dank für die schnelle Antwort! Der Dienst AuthenticationService führt HTTP-Anforderungen aus. Da ich den Controller teste, glaube ich nicht, dass dies eine Rolle spielen würde. Allerdings nahm ich Ihren Vorschlag und fügte den httpBackend-Mock mit expect hinzu, und nun funktioniert der Unit-Test! – cvk10

1

Vielleicht ein strittiger Punkt, um die Frage zu beantworten fast zwei Jahre, nachdem es gefragt wurde, aber die akzeptierte Antwort ist nicht ganz richtig. Das Problem ist, dass Sie nicht richtig spotten AuthenticationService. Sie sollten die Funktionalität des Dienstes vollständig ausspionieren, indem Sie nur testen, dass der Dienst vom Controller aufgerufen wurde, und die $httpBackend-Komponente für das Testen des Diensts speichern. Was Sie tun möchten, ist eine falsche AuthenticationService injizieren (sowie Schein Instanziierungen von Angular Services wie $q, $location, und $route, wenn wir Best Practices folgen) in die beforeEach, und dann deklarieren Sie es in der $controller Definition. Sie können Ihre Spione auch in den Block beforeEach aufnehmen.

describe('AuthCtrl', function(){ 

    var $q; 
    var $location; 
    var $controller; 
    var AuthenticationService; 
    var $route; 
    var deferred; 

    beforeEach(inject(function(_$controller_, $rootScope, _AuthenticationService_, _$q_, _$location_, _$route_){ 

    scope = $rootScope.$new(); 
    AuthenticationService = _AuthenticationService_; 
    $location = _$location_; 
    $route = _$route_; 
    $controller = _$controller_; 
    $q = _$q_; 
    deferred = $q.defer(); 

    spyOn(AuthenticationService, 'login').andReturnValue(deferred.promise); 
    spyOn($location, 'url'); 

    AuthCtrl = $controller('AuthCtrl', { 
     scope: scope, 
     AuthenticationService: AuthenticationService, 
     $route: $route, 
     $location: $location 
    }; 

    })); 

    it('should redirect the user on login', function(){ 
     deferred.resolve(); 
     scope.$apply(); 
     expect($location.url).toHaveBeenCalledWith('/tasks'); 
    }); 
}); 

Beachten Sie, dass es wichtig ist Ihre Controller-Definition das letzte Element in dem beforeEach Block zu machen, wenn Sie Ihre Variablen auf diese Weise definieren, sonst wird die Mocks nicht richtig und die Service-Methoden instanziiert wird tatsächlich aufgerufen werden , unabhängig von Spionen.

Verwandte Themen