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

IT技术 javascript jquery ajax jasmine bdd
2021-02-12 20:16:36

我正在尝试使用 Jasmine 为基本的 jQuery AJAX 请求编写一些 BDD 规范。我目前在独立模式下使用 Jasmine(即通过SpecRunner.html)。我已将 SpecRunner 配置为加载 jquery 和其他 .js 文件。任何想法为什么以下不起作用?has_returned 不会变成真的,甚至认为“yuppi!” 警报显示正常。

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 相关的博客/材料的指针将不胜感激。

6个回答

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

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

本答案所述

这是一个类似的单元测试,用于验证您的回调是否在 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) {

本答案所述

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

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
    });
}
我真的希望您的回答是 Jasmine 官方文档的一部分。非常清楚地回答了一个困扰我几天的问题。
2021-03-16 20:16:36
当前获取最新调用信息的方式是 $.ajax.calls.mostRecent()
2021-03-17 20:16:36
这个答案真的应该标记为这个问题的官方答案。
2021-03-20 20:16:36
+1 亚历克斯很好的答案。实际上,我遇到了类似的问题,为此我打开了一个使用 Deferred 对象测试 Ajax 请求的问题你能看看吗?谢谢。
2021-03-24 20:16:36
你将如何为普通的 JS ajax 实现它?
2021-04-06 20:16:36

查看 jasmine-ajax 项目:http : //github.com/pivotal/jasmine-ajax

它是一个插入式帮助程序(对于 jQuery 或 Prototype.js)在 XHR 层存根,以便请求永远不会发出。然后,您可以期待有关请求的所有信息。

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

它将 Ajax 调用排除在异步测试领域之外,并为您测试实际响应处理程序的工作方式提供了很大的灵活性。

@mnacos jasmine-ajax 最适用于单元测试,在这种情况下,您特别希望避免调用服务器。如果您正在进行集成测试,这可能不是您想要的,应该设计为单独的测试策略。
2021-03-19 20:16:36
感谢@jasminebdd,jasmine-ajax 项目看起来像是测试我的 js 代码的方式。但是,如果我想测试对服务器的实际请求,例如连接/集成测试,该怎么办?
2021-03-26 20:16:36

这是一个像这样的应用程序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();
 });
});
不确定这是否是版本问题,但我在 上出错.andCallFake.and.callFake改为使用谢谢。
2021-03-22 20:16:36
多谢,伙计。这个例子对我帮助很大!请注意,如果您使用的是 Jasmine > 2.0,则 andCallFake 的语法是 spyOn(jQuery, "ajax").and.callFake( /* your function */ );
2021-03-23 20:16:36

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

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

https://gist.github.com/946704

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