2014-11-05 62 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