2017-10-08 6 views
0

Dans mon application JS angulaire, j'ai un contrôleur principal qui prend en paramètre un userFactory. La userFactory se compose d'un objet appelé userService qui à son tour a un objet userDetails et certaines méthodes, y compris resetUserDetails. (voir plus bas)Utilisation de Jasmine spyOn avec la méthode d'un objet défini dans une usine

Dans le contrôleur principal, j'ai une fonction logOut qui appelle la méthode userFactory.userService.resetUserDetails. Je voudrais tester cette fonction de logOut avec le jasmin mais je reçois quelques erreurs. Je suis très nouveau à Jasmine alors excuses si c'est quelque chose qui me manque.

Donc d'abord dans ma suite Jasmine je crée un MainControllerSpec pour tester mon mainController.

Dans cette spécification j'injecte une usine appelée userFactory. Je suis en train de spyOn ma méthode resetUserDetails comme suit toutefois obtenir une erreur:

spyOn(userFactory, 'userService.resetUserDetails'); 

Erreur: userService.resetUserDetails() n'existe pas.

J'ai essayé ce processus en créant une fonction appelée test dans mon userFactory (en dehors de l'objet userService) et cela fonctionne bien donc au moins je sais que l'injection d'usine dans la spécification est bien configurée.
Toute aide grandement appréciée. Merci

MainControllerSpec.js

describe("MainController", function() { 
    beforeEach(angular.mock.module('mapModule', 'ngRoute','ngTouch', 'ngAnimate')); 
    var scope, userFactory; 

    beforeEach(inject(function($rootScope, $controller, _userFactory_){ 
     scope = $rootScope.$new(); 
     userFactory = _userFactory_; 
     $controller('mainController', { 
      $scope: scope 
     }); 
    })); 


    describe('The logOut function', function() { 
     it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() { 
      //spyOn takes in a factory and a method of that factory 
      spyOn(userFactory, 'userService.resetUserDetails'); 
      //spyOn(userFactory, 'test'); tried this and it works. 
      scope.logOut(); 
      expect(userFactory.userService.resetUserDetails).toHaveBeenCalled(); 
     }); 
    }); 

}); 

fonction déconnexions dans un mainController

$scope.logOut = function(){ 
     userFactory.userService.resetUserDetails(); 
     //userFactory.test(); //tried this with spyOn in jasmine 
    } 

de UserFactory

mapApp.factory('userFactory', function(){ 

    var userService = { 
     /* 
     * Initialize a userDetails object. 
     */ 
     userDetails : { 
      "userID" : null, 
      "facebookUserID" : "", 
      "facebookName" : "", 
      "facebookProfilePic" : "", 
      "userPrivilegeID" : 1, 
      "userToken" : "", 
      "isLoggedIn" : false 
     }, 
     resetUserDetails : function(){ 
      /* 
      * This method resets the userDetails object. 
      */ 
      this.userDetails = { 
       "userID" : null, 
       "facebookUserID" : "", 
       "facebookName" : "", 
       "facebookProfilePic" : "", 
       "userPrivilegeID" : 1, 
       "userToken" : "", 
       "isLoggedIn" : false 
      }; 
     } 
    }; 
    var test = function(){ 
     /* 
     * for testing spyOn in Jasmine 
     */ 
    }; 
    //return public API so that we can access it in all controllers 
    return{ 
     userService: userService, 
     test: test 
    }; 
}); 
+0

Ive juste écopé il. excuses. Ce qui suit fonctionne bien. spyOn (userFactory.userService, 'resetUserDetails'); – Sarah

+0

Habituellement, vous voudrez peut-être se moquer entièrement du service dans les tests du contrôleur au lieu d'espionner ses méthodes une par une. Par exemple. https://stackoverflow.com/a/46595428/3731501 – estus

+0

@estus ok merci pour le conseil. Je vais vérifier cela – Sarah

Répondre

1

Vous devez se moquer de votre userFactory avant d'injecter directement. Les objectifs des tests unitaires sont de tester les fichiers sous forme de boîtes noires, sans tester directement la logique des méthodes associées.

Pour eux, vous allez écrire votre fichier de spécifications pour le userFactory à la place.

Dans ce cas, ce que vous pouvez faire est quelque chose comme ce qui suit:

describe("MainController", function() { 
 

 
    beforeEach(angular.mock.module('mapModule', 'ngRoute', 'ngTouch', 'ngAnimate')); 
 
    var scope, userFactory; 
 

 
    // here mock the methods of your factory 
 
    beforeEach(module(function($provide) { 
 
    $provide.value('userFactory', { 
 
     myFirstObject: { 
 
     myFirstMethod: function() {} 
 
     } 
 
    }); 
 
    })); 
 

 
    beforeEach(inject(function($rootScope, $controller, _userFactory_) { 
 
    scope = $rootScope.$new(); 
 
    userFactory = _userFactory_; 
 
    $controller('mainController', { 
 
     $scope: scope 
 
    }); 
 
    })); 
 

 

 
    describe('The logOut function', function() { 
 
    it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() { 
 
     //here spy on the method and return what you would like to return in this test 
 
     // or if you don't need to manage the return, as it seems you don't, just use callThrough 
 
     spyOn(userFactory.myFirstObject, 'myFirstMethod').and.callThrough(); 
 
     scope.logOut(); 
 
     expect(userFactory.myFirstObject.myFirstMethod).toHaveBeenCalled(); 
 
    }); 
 
    }); 
 

 
});

+0

Merci. Je vais essayer ça demain. Bien que j'ai corrigé mon propre code comme vous pouvez le voir dans les commentaires ci-dessus. J'avais besoin de dire ceci: spyOn (userFactory.userService, 'resetUserDetails'); au lieu de cela: spyOn (userFactory, 'userService.resetUserDetails'); .. (parce que ma méthode est dans un objet appelé userService dans la userFactory) .. mais j'apprécie votre conseil et essayera ce que vous avez suggéré. merci – Sarah

+0

oh désolé n'a pas remarqué votre méthode était à l'intérieur de l'objet imbriqué, a changé le code dans la réponse – quirimmo

+0

merci. J'ai essayé ceci et cela fonctionne bien merci. Cependant, une chose supplémentaire que j'ai faite (avec merci à une autre personne dans les commentaires). J'ai créé un espion en utilisant jasmine.createSpy() alors $ provide.value ('userFactory', { myFirstObject: { maFirstMethod: jasmine.createSpy() } }); et puis je n'ai pas eu besoin d'utiliser spyOn dans le test de la suite mais j'ai continué avec le reste du code. Quoi qu'il en soit, votre réponse est correcte pour ma question, donc je vais l'accepter maintenant. je vous remercie beaucoup – Sarah