2014-07-16 10 views
14

Ich frage mich, wie sollte man mit Karma Test mit Angular.js + UI Router testen?Karma Tests mit Angular.js + UI Router

Ich habe den folgenden Status definiert: Welche hat zwei Resolves, die einige Daten abruft und bereitet die Daten für den Controller. (Von Ember Hintergrund, das macht eine Menge Sinn.)

$stateProvider 
    .state('users', { 
    resolve: { 
     getData: function (User) { 
     return User.query().$promise 
     }, 
     stateModels: function (getData) { 
     var models = {} 
     models.users = getData 
     return models 
     } 
    }, 
    url: '/', 
    templateUrl: '/views/users/index.html', 
    controller: 'UsersIndexCtrl' 
    }) 

Unsere UserIndexCtrl wie folgt aussieht: (die den aufgelöst stateModels nehmen und weist sie den $ Umfang, so die Ansicht kann es verwenden,)

app.controller('UsersIndexCtrl', [ 
    '$scope', '$state', 'stateModels', 
    function ($scope, $state, stateModels) { 

    $scope.users = stateModels.users 

    }]) 

Das funktioniert gut im Browser, ich sehe die richtigen Ergebnisse. Wenn es jedoch um Tests geht, gibt es mir seltsame Fehler. Hier

ist ein Beispiel Karma Unit-Test:

describe('controllers', function() { 

    var $httpBackend 
    , $rootScope 
    , $scope 
    , $state 
    , $httpBackend 
    , $controller 

    beforeEach(module('app')) 

    beforeEach(inject(function ($injector) { 
    $state = $injector.get('$state') 
    $rootScope = $injector.get('$rootScope') 
    $httpBackend = $injector.get('$httpBackend') 
    $scope = $rootScope.$new() 
    $controller = $injector.get('$controller') 
    })) 

    it('UserIndexCtrl should exist', inject(function() { 
    $httpBackend 
     .expect('GET', '/api/users') 
     .respond(200, {users: [ {}, {}, {} ]}) 

    $state.go('users') 
    $rootScope.$apply() 

    $controller('AdminZonesIndexCtrl', { $scope: $scope, $state: $state }); 
    $rootScope.$apply() 
    assert.equal($scope.users.length, 3) 
    })) 

}) 

Und ich sehe:

[$injector:unpr] Unknown provider: stateModelsProvider <- stateModels 
http://errors.angularjs.org/1.3.0-build.2937+sha.4adc44a/$injector/unpr?p0=stateModelsProvider%20%3C-%20stateModels 
Error: [$injector:unpr] Unknown provider: stateModelsProvider <- stateModels 
http://errors.angularjs.org/1.3.0-build.2937+sha.4adc44a/$injector/unpr?p0=stateModelsProvider%20%3C-%20stateModels 

Die Idee dabei ist:

  • Wir verspotten die API-Anforderung, so dass GET-Anfragen an/api/users werden ein Array von 3 Objekten zurückgeben.
  • Wir gehen in den Zustand namens Benutzer
  • Wir erwarten zu sehen, dass die $ scope.users ein Array von 3 Objekten sein sollte.
  • Von diesem Test haben wir beide im Router definierten Auflösungen getestet, und der Controller hat die aufgelösten Objekte korrekt zugewiesen.

Dank Bill

Antwort

26

Der Grund für Fehler ist, dass Sie zunächst Übergang zu einem Zustand sind, die Ihre UsersIndexCtrl mit einem neuen Rahmen instanziiert, aber dann anschließend eine weitere Instanz des Controllers (wieder zu schaffen, mit ein neuer Umfang) innerhalb des Tests. Die beiden sind unabhängig voneinander, und in der zweiten Instanz ist stateModels eine unbekannte/nicht verfügbare Abhängigkeit.

Also, während Ihre Ideen gültige Testprobleme sind, führen Sie im Wesentlichen einen End-to-End-Test in einer Komponententestumgebung durch. Sie sollten nicht wollen - auf eine spröde Abhängigkeit schaffen wird, so zu tun:

  • die Steuerung an die „Benutzer“ Zustand
  • gehören, die irgendwo in dem Zustandsübergang eine bestimmte HTTP-Anforderung
  • , dass die aufgerufen wird, Die stateModels-Abhängigkeit ist an den Bereich gebunden.

Von diesen Behauptungen betrifft nur die letzte den Controller. Unit Tests für Ihren Controller nicht Pflege wie/wann es instanziiert wurde oder wo die stateModels Abhängigkeit kam, sind sie nur mit dem eigenen Verhalten des Controllers betroffen.So lassen Sie uns dieses Verhalten aufgespalten:

Einheit das Testen des Controllers

Ihr erster Test auf das folgende reduziert werden sollte:

it('binds the users to the scope', function(){ 
    var stateModels = [{}, {}, {}]; 
    $controller('UserIndexCtrl', {$scope: $scope, stateModels: stateModels}); 
    assert.equal($scope.users, stateModels); 
}); 

Beachten Sie, dass, wie Sie mehr Tests hinzufügen, werden Sie wahrscheinlich möchte die Instantiierung des Controllers in einen beforeEach Block verschieben.

die Strecke testen

Die Sorge um eine Route zu testen ist wirklich das Anwendungsverhalten, für die Sie Protractor verschieben sollte. Wenn Sie jedoch insbesondere einen Komponententest für einen Zustand durchführen möchten, ist dies am besten durch Testen der Konfiguration des Zustands selbst möglich. Zum Beispiel:

it('resolves the stateModels dependency', function() { 
    var state = $state.get('users'); 
    assert.isDefined(state.resolve.stateModels); 
    // perform assertion that stateModels function resolves to what is expected 
    // Note: any such assertion should stub any dependency being used, to ensure 
    // we are testing in isolation. 
}); 

Ungeachtet dessen, ich persönlich wählen nicht zu Unit-Test-Routing/Wegekonfiguration und stattdessen eine solche Deckung durch e2e Tests mit Protractor erwerben.

+0

Diese hübsche Zusammenfassung meiner Probleme. – Bill

+0

@scarlz, ich bin neu in Mocha-Chai, könnten Sie mir bitte helfen mit ähnlichen Problem veröffentlicht unter http://stackoverflow.com/questions/28606056/mocha-cha-test-case-for-angular-configuration-file – mayank

+0

Das fasst mein Leben ziemlich zusammen. – Igor

Verwandte Themen