2015-07-03 6 views
6

Ho un metodo definito nel controller AngularJS che viene richiamato durante l'inizializzazione. Voglio testarlo usando Jasmine ("jasmine-core": "^2.3.4", "karma": "^0.12.37"). Seguo alcuni tutorial su Internet e le domande StackOverflow, ma non riesco a trovare la risposta giusta. Si prega di dare un'occhiata a questo codice:Test del controller del gelsomino, la spia attesa è stata chiamata

controller usersAddUserController:

(function() { 
    'use strict'; 

    angular.module('app.users.addUser') 
     .controller('usersAddUserController', ['$scope', 'usersAddUserService', function ($scope, usersAddUserService) { 

      usersAddUserService.getCountryPhoneCodes().then(function (phoneCodes) { 
       $scope.phoneCodes = phoneCodes; 
      }); 

     }]); 
}()); 

Jasmine prova:

(function() { 

    'use strict'; 

    describe('usersAddUserControllerUnitTest', function() { 
     var scope, deferred, objectUnderTest, mockedAddUserService; 

     beforeEach(module('app')); 

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

      function emptyPromise() { 
       deferred = $q.defer(); 
       return deferred.promise; 
      } 

      mockedAddUserService = { 
       getCountryPhoneCodes: emptyPromise 
      }; 

      objectUnderTest = $controller('usersAddUserController', { 
       $scope: scope, 
       usersAddUserService: mockedAddUserService 
      }); 
     })); 

     it('should call getCountryPhoneCodes method on init', function() { 
      //when    
      spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough(); 

      deferred.resolve(); 

      scope.$root.$digest(); 

      //then 
      expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled(); 
     }); 

    }); 
}()); 

Dopo aver eseguito i test, il messaggio di errore è:

PhantomJS 1.9.8 (Windows 7 0.0.0) usersAddUserControllerUnitTest should call getCountryPhoneCodes method on init FAILED

Expected spy getCountryPhoneCodes to have been called. 

I ovviamente manca qualcosa, ma non riesco a capire di cosa si tratta. Qualsiasi aiuto sarà apprezzato.

risposta

3

Stai spiando il mock dopo che è stato passato nel controller istanziato.

Prova questo:

describe('usersAddUserControllerUnitTest', function() { 
    var scope, deferred, objectUnderTest, mockedAddUserService, $controller; 

    beforeEach(module('app')); 

    beforeEach(inject(function ($rootScope, $q, _$controller_) { 
     scope = $rootScope.$new(); 

     function emptyPromise() { 
      deferred = $q.defer(); 
      return deferred.promise; 
     } 

     mockedAddUserService = { 
      getCountryPhoneCodes: emptyPromise 
     }; 

     $controller = _$controller_; 
    })); 

    function makeController() {  
     objectUnderTest = $controller('usersAddUserController', { 
      $scope: scope, 
      usersAddUserService: mockedAddUserService 
     }); 
    } 

    it('should call getCountryPhoneCodes method on init', function() { 
     //when 

     spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough(); 
     makeController(); 

     deferred.resolve(); 

     scope.$root.$digest(); 

     //then 
     expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled(); 
    }); 

}); 

EDIT Grazie @juunas per notare il bug nella mia soluzione

+0

Grazie per la risposta, ma sfortunatamente ottiene lo stesso errore con il tuo codice. Funziona per te? –

+0

In realtà non l'ho provato, sembrava proprio l'ovvio problema. Puoi inserire un breakpoint sul costruttore del controller e vedere se è effettivamente la spia che sta chiamando? – Martin

+0

Grazie mille ragazzi! Effettivamente @juunas aveva ragione, ora ho avuto il SUCCESSO. Se i juunas sono d'accordo, accetterò la risposta di Martin in ogni caso, mi aiuta molto :) –

1

È possibile fornire il finto in questo modo:

mockedAddUserService = { 
    getCountryPhoneCodes: emptyPromise 
}; 


beforeEach(function() { 
    module(function ($provide) { 
     $provide.value('usersAddUserService', mockedAddUserService); 
    }); 
}); 

EDIT:

Il codice dovrebbe essere (come io non posso provarlo) in questo modo:

(function() { 
    'use strict'; 

    describe('usersAddUserControllerUnitTest', function() {   
     beforeEach(module('app')); 

     var emptyPromise = function() { 
      var deferred = $q.defer(); 
      return deferred.promise; 
     } 

     var mockedAddUserService = { 
      getCountryPhoneCodes: emptyPromise 
     }; 

     beforeEach(function() { 
      module(function ($provide) { 
       $provide.value('usersAddUserService', mockedAddUserService); 
      }); 
     }); 

     var scope; 
     beforeEach(inject(function ($rootScope, $q, $controller) { 
      scope = $rootScope.$new(); 
      $controller('usersAddUserController', { 
       $scope: scope 
      }); 
     })); 

     it('should call getCountryPhoneCodes method on init', function() { 
      spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough(); 

      scope.$root.$digest(); 

      expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled(); 
     }); 

    }); 
}()); 
+0

Grazie per la risposta, ma potrebbe fornire il codice completo? Quando includo la tua soluzione nel mio codice ottengo: "TypeError: 'undefined' non è un oggetto (che valuta 'deferred.resolve')". –

+0

Grazie per il codice, proverò anche la tua soluzione e fornirò un feedback su ciò che è necessario fare di più. –