【问题标题】:unit testing angularjs $q.all - promise never completes单元测试 angularjs $q.all - 承诺永远不会完成
【发布时间】:2015-01-01 07:53:42
【问题描述】:

我正在尝试测试我构建的服务,该服务使用 Angular 的 $q Promises 实现。我正在使用 Karma、Mocha、Chai、Sinon、Sinon Chai 和 Chai as Promised 的组合。

我编写并返回承诺的所有测试都通过了,但拒绝或使用$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 的承诺实现进行测试,它可以正常工作。

PS 我实际上发现在 Mocha、Chai 或 Chai As Promised 的碗中某处花费了一些时间,并且 afterEach 挂钩在超时之后被调用。

【问题讨论】:

  • 如果我理解伪代码,看起来您在发送期望文本后才调用$scope.$apply()。您可以在解决/拒绝承诺后尝试调用它吗?
  • 其实我也试过了,我很快就会搞定这些测试。
  • @khanhto - 这是真的,@proloser 提到我只使用afterEach 进行清理。在我这样做的时候我没有想到。

标签: javascript angularjs unit-testing angular-promise


【解决方案1】:

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(),而不是在设置和评估之间。

【讨论】:

  • 如果您愿意,可以尝试在这个 plnk 上测试它,我很难设置它。我认为我的一个资源是无效的或什么的,因为我在控制台中收到一个错误,告诉我我错过了beforeEach。我从未尝试在浏览器中进行测试,因此我们将不胜感激,因此我们将不胜感激,以便我们查看此答案是否确实有效,并且我们还将提供在线参考,以便其他用户可以看到它。
  • 这就是我在评论中写的,如果在浏览器中设置它,我们将不胜感激,因为我从来没有这样做过。当然,如果您愿意,您可以制作一个 plnkr 并应用您的修复程序并证明它确实有效。在我的机器上本地执行它并说它可以工作它不会帮助其他遇到相同问题的用户。
  • 您的建议不起作用,我已经尝试过您之前的建议。这就是为什么我问您是否可以帮助在浏览器中设置测试,以便您也可以检查它以及其他用户是否可以工作。
【解决方案2】:

我试图找出为什么测试没有通过,尽管乍一看它们应该通过。当然,我必须将$scope.$apply();afterEach 移走,因为这不是@proloser 提到的打电话的地方。

即使我这样做了,测试仍然没有通过。我还在chai-as-promisedangular 上打开了问题,看看我是否得到任何输入/反馈,实际上我被告知它很可能不起作用。原因可能是因为 Angular $q 对摘要阶段的依赖在 chai-as-promsied 库中没有考虑。

因此,我使用 Q 而不是 $q 检查了测试,它工作得很好,从而加强了我的假设,即错误不在 chai-as-promised 库中。

我最终放弃了 chai-as-promised 并改用 Mocha 的 done 回调重写了我的测试(即使在幕后,chai-as-promised 也是如此):

"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();

    });

});

以上测试都将按预期通过。可能有其他方法可以做到这一点,但我不知道还有其他方法,所以如果其他人这样做,最好将其发布,以便其他人可以从中受益。

【讨论】:

  • @blacksonic - 没问题,我自己花了好几天才找到解决办法 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
相关资源
最近更新 更多