如何使用 Jasmine 验证 jQuery AJAX 事件?

问题描述 投票:0回答:7

我正在尝试使用 Jasmine 为基本的 jQuery AJAX 请求编写一些 BDD 规范。我目前在独立模式下使用 Jasmine(即通过

SpecRunner.html
)。我已将 SpecRunner 配置为加载 jquery 和其他 .js 文件。为什么以下不起作用的任何想法? has_returned 不会变为真,甚至认为“雅皮士!”警报显示正常。

describe("A jQuery ajax request should be able to fetch...", function() {

  it("an XML file from the filesystem", function() {
    $.ajax_get_xml_request = { has_returned : false };  
    // initiating the AJAX request
    $.ajax({ type: "GET", url: "addressbook_files/addressbookxml.xml", dataType: "xml",
             success: function(xml) { alert("yuppi!"); $.ajax_get_xml_request.has_returned = true; } }); 
    // waiting for has_returned to become true (timeout: 3s)
    waitsFor(function() { $.ajax_get_xml_request.has_returned; }, "the JQuery AJAX GET to return", 3000);
    // TODO: other tests might check size of XML file, whether it is valid XML
    expect($.ajax_get_xml_request.has_returned).toEqual(true);
  }); 

});

如何测试回调是否被调用?非常感谢任何指向与使用 Jasmine 测试异步 jQuery 相关的博客/材料的指针。

javascript jquery ajax jasmine bdd
7个回答
235
投票

我猜你可以做两种类型的测试:

  1. 伪造 AJAX 请求的单元测试(使用 Jasmine 的间谍),使您能够测试在 AJAX 请求之前和之后运行的所有代码。您甚至可以使用 Jasmine 伪造来自服务器的响应。这些测试会更快 - 而且它们不需要处理异步行为 - 因为没有任何真正的 AJAX 正在进行。
  2. 执行真实 AJAX 请求的集成测试。这些需要是异步的。
Jasmine 可以帮你做这两种测试

这里是一个示例,说明如何伪造 AJAX 请求,然后编写单元测试来验证伪造的 AJAX 请求是否转到正确的 URL:

it("should make an AJAX request to the correct URL", function() { spyOn($, "ajax"); getProduct(123); expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/products/123"); }); function getProduct(id) { $.ajax({ type: "GET", url: "/products/" + id, contentType: "application/json; charset=utf-8", dataType: "json" }); }

对于

Jasmine 2.0,请改用:

expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/products/123");

this answer中所述

这是一个类似的单元测试,用于在 AJAX 请求成功完成后验证您的回调是否已执行:

it("should execute the callback function on success", function () { spyOn($, "ajax").andCallFake(function(options) { options.success(); }); var callback = jasmine.createSpy(); getProduct(123, callback); expect(callback).toHaveBeenCalled(); }); function getProduct(id, callback) { $.ajax({ type: "GET", url: "/products/" + id, contentType: "application/json; charset=utf-8", dataType: "json", success: callback }); }

对于

Jasmine 2.0,请改用:

spyOn($, "ajax").and.callFake(function(options) {

this answer中所述

最后,您在别处暗示您可能想要编写发出真正 AJAX 请求的集成测试 - 用于集成目的。这可以使用 Jasmine 的异步功能来完成:waits()、waitsFor() 和 runs():

it("should make a real AJAX request", function () { var callback = jasmine.createSpy(); getProduct(123, callback); waitsFor(function() { return callback.callCount > 0; }); runs(function() { expect(callback).toHaveBeenCalled(); }); }); function getProduct(id, callback) { $.ajax({ type: "GET", url: "data.json", contentType: "application/json; charset=utf-8" dataType: "json", success: callback }); }
    

13
投票
查看jasmine-ajax项目:

http://github.com/pivotal/jasmine-ajax.

它是一个插入式帮助器(对于 jQuery 或 Prototype.js)在 XHR 层存根,因此请求永远不会消失。然后你可以期待所有你想要的请求。

然后它允许您为所有情况提供夹具响应,然后为您想要的每个响应编写测试:成功、失败、未经授权等。

它将 Ajax 调用带出异步测试领域,并为您提供了很大的灵活性来测试您的实际响应处理程序应该如何工作。


7
投票
这里是一个简单的示例测试套件 对于像这样的应用程序 js

var app = { fire: function(url, sfn, efn) { $.ajax({ url:url, success:sfn, error:efn }); } };

一个示例测试套件,它将根据 url regexp 调用回调

describe("ajax calls returns", function() { var successFn, errorFn; beforeEach(function () { successFn = jasmine.createSpy("successFn"); errorFn = jasmine.createSpy("errorFn"); jQuery.ajax = spyOn(jQuery, "ajax").andCallFake( function (options) { if(/.*success.*/.test(options.url)) { options.success(); } else { options.error(); } } ); }); it("success", function () { app.fire("success/url", successFn, errorFn); expect(successFn).toHaveBeenCalled(); }); it("error response", function () { app.fire("error/url", successFn, errorFn); expect(errorFn).toHaveBeenCalled(); }); });
    

5
投票
当我用 Jasmine 指定 ajax 代码时,我通过监视启动远程调用的任何依赖函数(比如 $.get 或 $ajax)来解决问题。然后我检索在其上设置的回调并离散地测试它们。

这是我最近举的一个例子:

https://gist.github.com/946704


0
投票
试试 jqueryspy.com 它提供了一种类似于 jquery 的优雅语法来描述您的测试,并允许在 ajax 完成后进行回调测试。它非常适合集成测试,您可以配置以秒或毫秒为单位的最大 ajax 等待时间。


0
投票
我觉得我需要提供一个更新的答案,因为 Jasmine 现在是 2.4 版本,一些功能已经从 2.0 版本开始改变。

因此,要验证回调函数已在您的 AJAX 请求中调用,您需要创建一个间谍,向其添加一个 callFake 函数,然后使用该间谍作为您的回调函数。事情是这样的:

describe("when you make a jQuery AJAX request", function() { it("should get the content of an XML file", function(done) { var success = jasmine.createSpy('success'); var error = jasmine.createSpy('error'); success.and.callFake(function(xml_content) { expect(success).toHaveBeenCalled(); // you can even do more tests with xml_content which is // the data returned by the success function of your AJAX call done(); // we're done, Jasmine can run the specs now }); error.and.callFake(function() { // this will fail since success has not been called expect(success).toHaveBeenCalled(); // If you are happy about the fact that error has been called, // don't make it fail by using expect(error).toHaveBeenCalled(); done(); // we're done }); jQuery.ajax({ type : "GET", url : "addressbook_files/addressbookxml.xml", dataType : "xml", success : success, error : error }); }); });

我已经完成了成功函数和错误函数的技巧,以确保即使您的 AJAX 返回错误,Jasmine 也会尽快运行规范。

如果你没有指定一个错误函数并且你的 AJAX 返回一个错误,你将不得不等待 5 秒(默认超时间隔)直到 Jasmine 抛出一个错误

Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

。您还可以像这样指定自己的超时时间:

it("should get the content of an XML file", function(done) { // your code }, 10000); // 10 seconds
    

0
投票
您可以使用

jasmine-ajax

库。这个库提供了一组函数和匹配器,允许您在 Jasmine 测试中模拟 AJAX 请求和响应。

这里是一个如何使用 Jasmine 验证 jQuery AJAX 请求的例子:

describe('my AJAX request', function() { beforeEach(function() { jasmine.Ajax.install(); }); afterEach(function() { jasmine.Ajax.uninstall(); }); it('should make an AJAX request to the correct URL', function() { // Set up the request var xhr = new XMLHttpRequest(); xhr.open('GET', '/my-api'); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { console.log('success!'); } }; xhr.send(); // Verify the request expect(jasmine.Ajax.requests.mostRecent().url).toBe('/my-api'); expect(jasmine.Ajax.requests.mostRecent().method).toBe('GET'); expect(jasmine.Ajax.requests.mostRecent().requestHeaders['Content-Type']).toBe('application/json'); }); });
在这个例子中,我们首先在

jasmine-ajax

块中安装
beforeEach
库。然后,我们在 
it
 块中设置一个基本的 jQuery AJAX 请求。最后,我们使用 
jasmine.Ajax.requests.mostRecent()
 函数检索最近的 AJAX 请求,然后使用 
expect
 函数验证请求具有正确的 URL、方法和标头。

您还可以使用

jasmine.Ajax.requests.filter

 函数根据其 URL、方法或标头检索特定的 AJAX 请求。此外,您可以使用 
jasmine.Ajax.requests.count
 函数来检查在测试期间发出了多少 AJAX 请求。

© www.soinside.com 2019 - 2024. All rights reserved.