如何使用Jasmine和/或Sinon正确地测试jQuery的.ajax()承诺?

时间:2012-10-30 22:15:14

标签: unit-testing jquery jasmine sinon

我有一个相当简单的函数,它返回一个jQuery .ajax()承诺:

CLAW.controls.validateLocation = function(val, $inputEl) {
    return $.ajax({
        url: locationServiceUrl + 'ValidateLocation/',
        data: {
            'locationName': val
        },
        beforeSend: function() {
            $inputEl.addClass('busy');
        }
    }).done(function(result) {
        // some success clauses
    }).fail(function(result) {
        // some failure clauses
    }).always(function() {
        // some always clauses
    });
}

在大多数情况下,这个新的promises接口就像一个梦想,当使用jQuery的.ajax()时,消除回调金字塔非常棒。但是,我不能为我的生活弄清楚如何使用Jasmine和/或Sinon正确测试这些承诺:

  1. 所有Sinon的文档都假设您使用的是旧式学校 回调;我没有看到如何使用它的单一示例 许/ deferreds

  2. 当试图使用Jasmine或Sinon间谍监视$ .ajax时, 间谍有效地覆盖了承诺,所以donefail, ajax函数中不再存在always子句,因此承诺永远不会解决并抛出错误

  3. 我真的很喜欢一个或两个如何使用前面提到的测试库测试这些新的jQuery .ajax()promises的例子。我已经相当强烈地搜索了'网,并没有真正挖掘任何东西这样做。我找到的一个资源是使用Jasmine.ajax提到的,但我想尽可能避免这种情况,因为Sinon提供了大部分开箱即用的相同功能。

4 个答案:

答案 0 :(得分:106)

实际上并不复杂。只需返回一个承诺并根据您的情况解决它。

例如:

spyOn($, 'ajax').andCallFake(function (req) {
    var d = $.Deferred();
    d.resolve(data_you_expect);
    return d.promise();
});

成功,或

spyOn($, 'ajax').andCallFake(function (req) {
    var d = $.Deferred();
    d.reject(fail_result);
    return d.promise();
});

失败。

对于Jasmine 2.0,语法略有改变:

spyOn($, 'ajax').and.callFake(function (req) {});

Jasmine 2.0中不存在.andCallFake()方法

答案 1 :(得分:16)

沿着这些方面的东西/与sinon和jQuery延迟

ajaxStub = sinon.stub($, "ajax");

function okResponse() {
  var d = $.Deferred();
  d.resolve( { username: "testuser", userid: "userid", success: true } );
  return d.promise();
};

function errorResponse() {
 var d = $.Deferred();
 d.reject({},{},"could not complete");
 return d.promise();
};

ajaxStub.returns(okResponse());
ajaxStub.returns(errorResponse());

答案 2 :(得分:0)

这是一个简单的方法,仅使用javascript。

quoteSnapshots: function (symbol, streamId) {
                var FakeDeferred = function () {
                    this.error = function (fn) {
                        if (symbol.toLowerCase() === 'bad-symbol') {
                            fn({Error: 'test'});
                        }
                        return this;
                    };
                    this.data = function (fn) {
                        if (symbol.toLowerCase() !== 'bad-symbol') {
                            fn({});
                        }
                        return this;
                    };
                };

                return new FakeDeferred();
            }

每个回调中的if语句都是我在测试中用来驱动成功或错误执行的。

答案 3 :(得分:0)

如果您使用.complete()之类的内容,@ ggozad提供的解决方案将无效。

但是,讽刺的是,jasmine做了一个插件来完成这个:http://jasmine.github.io/2.0/ajax.html

beforeEach(function() {
  jasmine.Ajax.install();
});

afterEach(function() {
  jasmine.Ajax.uninstall();
});

//in your tests
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');