2014-11-05 83 views
8

我試圖測試一個服務,我使用Angular的$q實現Promise。我將Karma,Mocha,Chai,Sinon,Sinon Chai和Chai視爲承諾。

我編寫並返回的所有測試都通過了,但拒絕或使用$q.all([ ... ])的測試通過。我嘗試了所有我能想到的,但我似乎無法找到問題所在。

以下是我所測試的縮小版本:

"use strict"; 


describe("Promise", function() { 

    var $rootScope, 
     $scope, 
     $q; 

    beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) { 
     $rootScope = _$rootScope_; 
     $q = _$q_; 
     $scope = $rootScope.$new(); 
    })); 

    afterEach(function() { 
     $scope.$apply(); 
    }); 

    it("should resolve promise and eventually return", function() { 

     var defer = $q.defer(); 

     defer.resolve("incredible, this doesn't work at all"); 

     return defer.promise.should.eventually.deep.equal("incredible, this doesn't work at all"); 
    }); 

    it("should resolve promises as expected", function() { 

     var fst = $q.defer(), 
      snd = $q.defer(); 

     fst 
      .promise 
      .then(function (value) { 
       value.should.eql("phew, this works"); 
      }); 

     snd 
      .promise 
      .then(function (value) { 
       value.should.eql("wow, this works as well"); 
      }); 

     fst.resolve("phew, this works"); 
     snd.resolve("wow, this works as well"); 

     var all = $q.all([ 
      fst.promise, 
      snd.promise 
     ]); 

     return all.should.be.fullfiled; 
    }); 

    it("should reject promise and eventually return", function() { 
     return $q.reject("no way, this doesn't work either?").should.eventually.deep.equal("no way, this doesn't work either?"); 
    }); 

    it("should reject promises as expected", function() { 

     var promise = $q.reject("sadly I failed for some stupid reason"); 

     promise 
      ["catch"](function (reason) { 
       reason.should.eql("sadly I failed for some stupid reason"); 
      }); 

     var all = $q.all([ 
      promise 
     ]); 

     return all.should.be.rejected; 
    }); 

}); 

第三,最後和第一個測試是失敗的。其實它不會失敗,它只是在超時超時後解決,我得到一個Error: timeout of 2000ms exceeded

編輯:我剛剛試過用Kris Kowal的承諾實施測試,它工作得很好。

P.S.我實際上發現在摩卡,柴或Chai As Promised的碗中有一段時間,並且afterEach掛鉤被調用的時間晚於超時。

+0

如果我理解僞代碼,它看起來好像你沒有調用'$ scope。$ apply()',直到你發佈了期望值。你能否在你解決/拒絕承諾後嘗試調用它? – 2014-11-07 22:22:43

+0

我實際上已經嘗試過了,我會盡快完成這些測試。 – Roland 2014-11-08 10:02:13

+0

運行'$ scope。$ apply()'在afterEach'中可能會成爲一個問題,如果你期望在afterEach運行之前承諾的價值 – 2014-11-09 03:41:04

回答

3

我試圖找出爲什麼測試沒有通過,即使乍一看他們應該。當然,我不得不將$scope.$apply();afterEach移開,因爲那不是所謂的@proloser所提及的地方。

即使我已經這樣做了,測試仍然沒有通過。我還在chai-as-promisedangular上打開了一些問題,看我是否收到任何意見和反饋,並且實際上我已被告知最有可能不工作。原因可能是因爲角度$q對消化階段的依賴,這在梳理圖書館中沒有考慮到。

因此,我用Q而不是$q檢查了測試,結果很好,因此加強了我的假設,即錯誤不在於承諾的庫中。

我最終放棄柴作爲許諾的,我已經用摩卡的done回調,而不是重寫我的測試(即使在幕後,柴作爲許諾的不一樣):

"use strict"; 


describe("Promise", function() { 

    var $rootScope, 
     $scope, 
     $q; 

    beforeEach(angular.mock.inject(function (_$rootScope_, _$q_) { 
     $rootScope = _$rootScope_; 
     $q = _$q_; 
     $scope = $rootScope.$new(); 
    })); 

    it("should resolve promise and eventually return", function (done) { 

     var defer = $q.defer(); 

     defer 
      .promise 
      .then(function (value) { 
       value.should.eql("incredible, this doesn't work at all"); 
       done(); 
      }); 

     defer.resolve("incredible, this doesn't work at all"); 

     $scope.$apply(); 

    }); 

    it("should resolve promises as expected", function (done) { 

     var fst = $q.defer(), 
      snd = $q.defer(); 

     fst 
      .promise 
      .then(function (value) { 
       value.should.eql("phew, this works"); 
      }); 

     snd 
      .promise 
      .then(function (value) { 
       value.should.eql("wow, this works as well"); 
      }); 

     fst.resolve("phew, this works"); 
     snd.resolve("wow, this works as well"); 

     var all = $q.all([ 
      fst.promise, 
      snd.promise 
     ]); 

     all 
      .then(function() { 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

    it("should reject promise and eventually return", function (done) { 

     $q 
      .reject("no way, this doesn't work either?") 
      .catch(function (value) { 
       value.should.eql("no way, this doesn't work either?"); 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

    it("should reject promises as expected", function (done) { 

     var promise = $q.reject("sadly I failed for some stupid reason"); 

     promise 
      ["catch"](function (reason) { 
       reason.should.eql("sadly I failed for some stupid reason"); 
      }); 

     var all = $q.all([ 
      promise 
     ]); 

     all 
      .catch(function() { 
       done(); 
      }); 

     $scope.$apply(); 

    }); 

}); 

上述測試將全部按預期順利完成。可能還有其他方法可以做到,但我無法弄清楚其他方式,所以如果其他人做的話,發佈它可以讓其他人從中受益,那將是非常棒的。

+0

謝謝你,我節省了我的時間 – Blacksonic 2015-02-23 08:49:42

+0

@blacksonic - 沒問題,我花了幾天時間,直到我找到一個修復:) – Roland 2015-02-23 15:25:16

13

afterEach()用於清理,而不是用於在準備之後但在測試之前執行代碼。 $scope.$apply()也沒有清理。

你需要做以下幾點:

// setup async behavior 
var all = $q.all(x.promise, y.promise) 

// resolve your deferreds/promises 
x.reject(); y.reject(); 

// call $scope.$apply() to 'digest' all the promises 
$scope.$apply(); 

// test the results 
return all.should.be.rejected; 

你做一個$apply()後,您的測試完成,而不是在設置和評價之間。

+0

如果你希望你可以嘗試在[plnk](http://plnkr.co/edit/IusDwx7ERoiqiUYKwqKn?p=preview)上測試它,我很難設置它。我認爲我的一個資源是無效的或者是某種東西,因爲我在控制檯中發現一個錯誤,告訴我錯過了'beforeEach'。我從來沒有嘗試過在瀏覽器中進行測試,所以有些幫助讓它起作用,所以我們可以看到這個答案是否真的有效,並且我們還會有一個在線參考,以便其他用戶可以看到它。 – Roland 2014-11-10 15:10:02

+0

這就是我在評論中寫到的,如果在瀏覽器中設置它,可能會有一些幫助,因爲我從來沒有這樣做過。如果你想要的話,你可以製作一個plnkr並應用你的修補程序並顯示它確實有效。在我的機器上進行本地操作並說它可以工作,這對其他用戶偶然遇到同樣問題無濟於事。 – Roland 2014-11-11 13:53:30

+0

你的建議不起作用,我已經嘗試過你以前的建議。這就是爲什麼我問你是否可以幫助在瀏覽器中設置測試,以便你可以檢查它以及其他用戶,如果它可以工作。 – Roland 2014-11-14 07:54:31