unit testing angularjs $ q.all - promise永远不会完成

时间:2014-11-05 07:33:15

标签: javascript angularjs unit-testing angular-promise

我试图测试我构建的服务,该服务使用Angular的$q Promises实现。我使用了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;
    });

});

第3次,最后一次和第一次测试是失败的。实际上它没有失败,它只是在超时超时后才解决,我得到Error: timeout of 2000ms exceeded

编辑:我刚刚尝试使用Kris Kowal的承诺实施测试,并且它可以正常使用。

PS 我实际上发现在Mocha,Chai或Chai As Bowl中的某个地方花了一些时间,并且afterEach挂钩会在超时后调用

2 个答案:

答案 0 :(得分: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(),而不是在设置和评估之间。

答案 1 :(得分:3)

我试图找出为什么测试没有通过,即使乍一看他们应该。当然,我必须从$scope.$apply();移动afterEach,因为这不是@proloser提到的地方。

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

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

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

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

    });

});

以上测试将全部按预期通过。可能还有其他方法可以做到这一点,但我无法弄清楚其他方法,所以如果有其他人这样做,那么将它发布以便其他人可以从中获益将会很棒。