2014-12-06 61 views
9

我目前正在嘗試使用SinonJS單元測試我的角度服務,但一直在遇到問題,並希望有人可能闡明爲什麼會發生這種情況。我重建了我目前的項目來說明手頭的問題。角度單元測試 - 嘲笑方法/關閉在相同的服務

我還提供了一個DEMO

我有一個服務,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 
     } 
    } 

}()); 

在這種服務,我的方法getAdults使用getFamily,對結果進行過濾,並返回數據。

在我的單元測試中,我試圖模擬getFamily並查看該方法是否被調用。現在,這是哪裏出了問題提出了自己......

我試過被刪空的方法和覆蓋當前的方法,像這樣的第一件事:

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

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

然後我去考getAdults是否調用getFamily方法:

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

測試失敗,存根方法是不是叫......

我調試,並找出ŧ帽子雖然功能實際上已經改變了: enter image description here

該服務仍持有引用(關閉)的服務創建時幹什麼用的方法是:

enter image description here

我最初的想法是我沒有正確存根方法。然後我試圖用$provide$provide.value)以及$injector decorator覆蓋該方法,最後我得到了相同的結果(關閉保持原始方法)。

對此的解決方案是使用this

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

不過,我不明白爲什麼我必須這樣做。

總之,沒有人知道:

  • 如何嘲笑在相同的服務的另一種方法,而不必使用this
  • 如何模擬出一個閉合可變中一個單元測試

非常感謝你的時間。

+0

看來你plunker不再可用 – sam 2014-12-16 11:23:47

回答

5

當您在對象上存根方法時,該對象的屬性被重寫,而不是它引用的原始函數。

舉個例子來說,這個代碼:

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

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

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

更改myObj.prop沒有改變原有的功能,myFunction仍然存在在自己的權利。但是,myObj.prop已失去對myFunction的引用。如果這是在sinon世界,stubbing只是將myObj.prop的引用更改爲存根對象。

這就是爲什麼當在一個服務中測試代碼時,它調用同一服務中的另一個函數時,該代碼需要引用服務返回的同一個對象。如果你想避免使用this關鍵字隨處可見,你可以組織你的服務,像這樣:

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

我覺得這個答案應該得到獎勵,這是非常明確的,完整的 – sam 2014-12-16 11:25:42