2014-12-06 9 views
9

Ich bin derzeit versucht zu Unit-Test meine eckigen Service mit SinonJS, aber habe in ein Problem und hatte gehofft, jemand könnte möglicherweise etwas Licht auf, warum dies auftritt. Ich habe mein aktuelles Projekt rekonstruiert, um das Problem zu illustrieren.Angular Unit Testing - Mocking Methoden/Verschlüsse in der gleichen Service

Ich habe auch ein DEMO

Ich habe einen Dienst, peopleService:

(function(){ 

    angular.module('myApp') 
    .factory('peopleService', peopleService); 

    peopleService.$inject = ['$q']; 

    function peopleService ($q){ 
     var people = ['Homer', 'Marge', 'Bart', 'Lisa', 'Maggie']; 

     // in actual project, this makes an http request 
     function getFamily() { 
     return people; 
     } 

     function getAdults(){ 
     var family = getFamily(); 
     return family.filter(function (person){ 
      return person === 'Homer' || person === 'Marge'; 
     }); 
     } 

     return { 
     getFamily: getFamily, 
     getAdults: getAdults 
     } 
    } 

}()); 

In diesem Dienst, meine Methode getAdults verwendet getFamily, filtert die Ergebnisse und die Daten zurückgibt.

In meinem Komponententest versuche ich getFamily zu verspotten und zu sehen, ob diese Methode aufgerufen wird. Nun ist dies, wo das Problem selbst präsentiert ...

Das erste, was ich versuchte, wurde die Methode Anstoßen und die aktuelle Methode überschrieben wird, etwa so:

beforeEach(function(){ 
    module('myApp'); 

    inject(function (_peopleService_){ 
    peopleService = _peopleService_; // get the service 
    sinon.stub(peopleService, 'getFamily'); // stub it 
    }); 
}); 

ich dann gehen Sie zu testen, ob getAdults ruft die getFamily Methode:

it('getAdults should call "getFamily" once', function(){ 
    peopleService.getAdults(); 
    expect(peopleService.getFamily.calledOnce).toBe(true); 
}); 

der Test schlägt fehl und die Stub-Methode aufgerufen wird nicht ...

ich debuggen und finden Sie heraus t Hut, obwohl die Funktion in der Tat hat sich geändert: enter image description here

Der Service hält noch eine Referenz (Verschluss), was das Verfahren verwendet werden soll, wenn der Dienst erstellt wurde:

enter image description here

Mein erster Gedanke war, Ich habe die Methode nicht korrekt gestempelt. Ich versuchte dann, die Methode zu überschreiben, indem ich $provide ($provide.value) sowie $injector decorator benutzte und ich endete das gleiche Ergebnis zu bekommen (Schließung hielt auf der ursprünglichen Methode).

Eine Lösung dieses Problems wäre this zu verwenden:

function getAdults(){ 
    var family = this.getFamily(); // <-- by using this.getFamily would reference the mock 
    return family.filter(function (person){ 
     return person === 'Homer' || person === 'Marge'; 
    }); 
    } 

Aber ich verstehe nicht, warum ich dies zu tun haben. Kurz

In, weiß jemand:

  • wie ein anderes Verfahren in dem gleichen Dienst verspotten ohne this
  • wie verspotten eine Verschlussgröße in einem Unit-Test
verwenden

Vielen Dank für Ihre Zeit.

+0

scheint Ihr Plunker nicht mehr verfügbar ist – sam

Antwort

5

Wenn Sie eine Methode für ein Objekt stubben, wird die -Eigenschaft dieses Objekts überschrieben, nicht die ursprüngliche Funktion, auf die sie verweist.

Nehmen wir zum Beispiel, dieser Code:

function myFunction() {}; 
var myObj = { prop: myFunction }; 

myObj.prop === myFunction; // true 
myObj.prop = 'changed'; 

typeof myFunction === 'function'; // true 
myObj.prop === myFunction; // false 

myObj.prop ändern nicht die ursprüngliche Funktion ändern, besteht myFunction noch in seinem eigenen Recht. myObj.prop hat jedoch seinen Verweis auf myFunction verloren. Wenn dies in Sinon-Welt war, änderte Stubbing einfach die Referenz von myObj.prop zu einem Stub-Objekt.

Aus diesem Grund muss beim Testen von Code in einem Service, der eine andere Funktion im selben Service aufruft, dieser Code auf dasselbe Objekt verweisen, das vom Service zurückgegeben wird. Wenn Sie überall mit dem this Schlüsselwort vermeiden möchten, können Sie Ihren Service-Struktur wie folgt:

angular.module('myApp') 
    .factory('peopleService', peopleService); 

peopleService.$inject = ['$q']; 

function peopleService ($q){ 
    var service = { 
    getFamily: getFamily, 
    getAdults: getAdults 
    }; 

    return service; 

    function getFamily() { 
    // ... 
    } 

    function getAdults(){ 
    var family = service.getFamily(); // <-- reference service.getFamily() 
    // ... 
    } 
} 
+0

Ich denke, diese Antwort sollte die Belohnung bekommen, es ist ziemlich klar und vollständig – sam