2016-07-26 12 views
0

Ich füge einige Tests zu einer Ionenanwendung hinzu, die Karma und Jasmin verwendet. In diesem Moment versuche ich, die Tests für den eckigen Login-Controller durchzuführen. Es scheint jedoch nicht zu sein, die inject-Sätze auszuführen, die den Controller erzeugen und alle externen Abhängigkeiten verspotten. Hier ist der Code Ich verwende:Karma/Jasmin-Test der Ionenanwendung, der Controller nicht einspritzt

login.controller.js

(function() { 
    var app = angular.module("myApp"); 

    app.controller("LoginController", function($translate, $state, $ionicPopup, $localStorage, sessionService, userService) { 
    var vm = this; 

    vm.email = null; 
    vm.password = null; 

    vm.login = function() { 
     $localStorage.email = vm.email; 
     $localStorage.password = vm.password; 

     sessionService.login().then(
     function(data) { 
      if (userService.isAuthenticated()) { 
      // User is logged, go to the next state 
      $state.go("next_state"); 
      } else { 
      // User is not logged (invalid credentials), show an alert message 
      var alertPopup = $ionicPopup.alert({ 
       title: $translate.instant("LOGIN_FAIL_TITLE"), 
       template: $translate.instant("LOGIN_FAIL_MESSAGE") 
      }); 
      } 
     } 
    ); 
    } 
    }); 
})(); 

login.controller.tests.js

describe("LoginController", function() { 
    var controller, 
     deferredLogin, 
     translateMock, 
     stateMock, 
     ionicPopupMock, 
     localStorageMock, 
     sessionServiceMock, 
     userServiceMock; 

    beforeEach(module("myApp")); 

    beforeEach(module(function($provide, $urlRouterProvider) { 
    $provide.value("$ionicTemplateCache", function() {}); 
    $urlRouterProvider.deferIntercept(); 
    })); 

    beforeEach(inject(function($controller, $q) { 
    deferredLogin = $q.defer(); 

    sessionServiceMock = { 
     login: jasmine.createSpy("login spy") 
        .and.returnValue(deferredLogin.promise) 
    }; 

    translateMock = jasmine.createSpyObj("$translate spy", ["instant"]); 

    stateMock = jasmine.createSpyObj("$state spy", ["go"]); 

    ionicPopupMock = jasmine.createSpyObj("$ionicPopup spy", ["alert"]); 

    localStorageMock = jasmine.createSpyObj("$localStorage spy", ["getItem"]); 

    userServiceMock = jasmine.createSpyObj("userService spy", ["isAuthenticated"]); 

    controller = $controller("LoginController", { 
     "$translate": translateMock, 
     "$state": stateMock, 
     "$ionicPopup": ionicPopupMock, 
     "$localStorage": localStorageMock, 
     "sessionService": sessionServiceMock, 
     "userService": userServiceMock 
    }); 
    })); 

    describe("#login", function() { 
    beforeEach(inject(function(_$rootScope_) { 
     $rootScope = _$rootScope_; 
     controller.email = "[email protected]"; 
     controller.password = "foobarfoo"; 
     controller.login(); 
    })); 

    it("should call login on sessionService", function() { 
     expect(sessionServiceMock.login).toHaveBeenCalledWith("[email protected]", "foobarfoo"); 
    }); 

    describe("when the login is executed", function() { 
     it("if successful, should change state to next_state", function() { 
     deferredLogin.resolve(); 
     $rootScope.$digest(); 
     expect(stateMock.go).toHaveBeenCalledWith("next_state"); 
     }); 

     it("if unsuccessful, should show a popup", function() { 
     deferredLogin.reject(); 
     $rootScope.$digest(); 
     expect(ionicPopupMock.alert).toHaveBeenCalled(); 
     }); 
    }); 
    }); 
}); 

Ich habe alle Orte durchsuchen versuchen verschiedene Lösungen, die ich gefunden habe, aber ich bekomme immer die gleichen Ergebnisse:

... 
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login should call login on sessionService FAILED 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    TypeError: undefined is not an object (evaluating 'sessionServiceMock.login') in unit-tests/controllers/login.controller.tests.js (line 63) 
    unit-tests/controllers/login.controller.tests.js:63:32 
    [email protected]://localhost:9876/context.js:151:17 
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login when the login is executed if successful, should change state to capture_image FAILED 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    TypeError: undefined is not an object (evaluating 'deferredLogin.resolve') in unit-tests/controllers/login.controller.tests.js (line 68) 
    unit-tests/controllers/login.controller.tests.js:68:22 
    [email protected]://localhost:9876/context.js:151:17 
PhantomJS 2.1.1 (Linux 0.0.0) LoginController #login when the login is executed if unsuccessful, should show a popup FAILED 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:13691:24 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17878:12 
    [email protected]/home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17800:30 
    [email protected]/home/user/NSS/my-app/www/lib/angular-mocks/angular-mocks.js:2922:60 
    [email protected]://localhost:9876/context.js:151:17 
    /home/user/NSS/my-app/www/lib/ionic/js/ionic.bundle.js:17918:53 
    TypeError: undefined is not an object (evaluating 'deferredLogin.reject') in unit-tests/controllers/login.controller.tests.js (line 74) 
    unit-tests/controllers/login.controller.tests.js:74:22 
    [email protected]://localhost:9876/context.js:151:17 
... 

Ich kann nicht verstehen, was ich falsch mache. Danke im Voraus.

UPDATE:

Als Matthew Green sagt, ich habe die Art, wie die Tests geschrieben werden geändert. Nun folgen sie seinen Empfehlungen und ich habe auch einige weitere Injektionen gegeben, die erforderlich sind:

describe("LoginController", function() { 
    var controller, 
     stateMock, 
     ionicPopupMock, 
     localStorageMock, 
     sessionServiceMockPromise, 
     sessionServiceMock; 

    // Load the application module 
    beforeEach(module("myApp")); 

    // Avoid trying to load all templates of the application 
    beforeEach(module(function($provide, $urlRouterProvider) { 
    $provide.value("$ionicTemplateCache", function() {}); 
    $urlRouterProvider.deferIntercept(); 
    })); 

    // Avoid asynchronous loader of the translations (problem with the angular-translate-design) 
    beforeEach(module(function($provide, $translateProvider) { 
    $provide.factory("customLoader", function($q) { 
     return function() { 
     var deferred = $q.defer(); 
     deferred.resolve({}); 
     return deferred.promise; 
     }; 
    }); 

    $translateProvider.useLoader("customLoader"); 
    })); 

    // Instanciate and initialize the controller and mocks 
    beforeEach(inject(function($controller, $q) { 
    sessionServiceMockPromise = $q.defer(); 
    sessionServiceMock = jasmine.createSpyObj("sessionServiceMock", ["login"]); 
    sessionServiceMock.login.and.callFake(function() { 
     return sessionServiceMockPromise.promise; 
    }); 

    stateMock = jasmine.createSpyObj("$state spy", ["go"]); 

    ionicPopupMock = jasmine.createSpyObj("$ionicPopup spy", ["alert"]); 

    localStorageMock = jasmine.createSpyObj("$localStorage spy", ["getItem"]); 

    controller = $controller("LoginController", { 
     "$state": stateMock, 
     "$ionicPopup": ionicPopupMock, 
     "$localStorage": localStorageMock, 
     "sessionService": sessionServiceMock 
    }); 
    })); 

    describe("#login", function() { 
    beforeEach(inject(function(_$rootScope_) { 
     $rootScope = _$rootScope_; 
     controller.login(); 
     sessionServiceMockPromise.resolve(); 
    })); 

    it("should call login on sessionService", function() { 
     expect(sessionServiceMock.login).toHaveBeenCalledWith(); 
    }); 

    describe("when the login is executed", function() { 
     it("if successfull, should change state to capture_image", inject(function(userService) { 
     spyOn(userService, "isAuthenticated").and.callFake(function() { return true; }); 
     $rootScope.$digest(); 
     expect(stateMock.go).toHaveBeenCalledWith("nextState"); 
     })); 

     it("should show a popup", inject(function(userService) { 
     spyOn(userService, "isAuthenticated").and.callFake(function() { return false; }); 
     $rootScope.$digest(); 
     expect(ionicPopupMock.alert).toHaveBeenCalled(); 
     })); 
    }); 
    }); 
}); 
+0

'undefined ist kein Objekt' ergibt hier keinen Sinn. Phantomjs neigt dazu, Fehlermeldungen zu verschlucken. Versuchen Sie es in einem anderen Browser (Chrome) auszuführen und überprüfen Sie die Fehler. – estus

Antwort

1

Es sieht aus wie Ihre sessionService.login() ist eine Funktion, die ein Versprechen zurückgeben sollte. In diesem Fall sehe ich ein paar Probleme mit dem, was Sie haben.

Erstens, ich weiß nicht, warum Sie diesen einen Service anders als den Rest einrichten. Dies könnte sehr wahrscheinlich einige Ihrer Probleme sein. Wenn Sie es genauso einrichten wie die anderen, würde es ungefähr so ​​aussehen.

var sessionServiceMockPromise = $q.defer(); 
sessionServiceMock = jasmine.createSpyObj('sessionServiceMock', ['login']); 
sessionServiceMock.login.and.callFake(function() { 
    return sessionServiceMockPromise.promise; 
}); 

In diesem wird festgestellt, dass Login-Funktion, die ein Versprechen zurückgibt. Mit sessionServiceMockPromise können Sie jetzt in Ihren Tests sessionServiceMockPromise.resolve([data]) (oder reject()) aufrufen, um das Ergebnis Ihres Versprechens zu sehen.

Zweitens sagt Ihr Test, dass er erwartet, dass der Login mit zwei Variablen aufgerufen wird. Nein, wo in Ihrem Code für den Dienst oder den Test sehe ich, dass dies eine Funktion ist, die Variablen akzeptiert. Ein besserer Test könnte sein, dass er aufgerufen wird oder dass der Zustand auf das eingestellt ist, was Sie erwarten würden.