如何伪造jquery.ajax()响应?

Stu*_*ser 37 javascript testing ajax jquery unit-testing

我正在为一个生成AJAX调用的JavaScript编写一些QUnit测试.

为了隔离,我覆盖$.ajax了将AJAX调用的参数数组写入变量.这可以测试方法如何使用AJAX函数,但是我很难测试成功处理程序$.load()

http://api.jquery.com/load/上的文档:

当检测到成功响应时(即当textStatus为"success"或"notmodified"时),.load()将匹配元素的HTML内容设置为返回的数据.

所以我试图返回一个对象,该对象包含与成功处理程序的变量同名的对象:

    //Mock ajax function
    $.ajax = function (param) {
        _mockAjaxOptions = param;
        var fakeAjaxSuccess = { responseText: "success", textStatus: "success", XMLHttpRequest: "success" };
        return fakeAjaxSuccess;
    };
Run Code Online (Sandbox Code Playgroud)

但这种方法并没有奏效.

如何复制成功的AJAX调用的行为?

use*_*074 24

这个问题有几年了,对于新版本的jQuery已经有所改变.

要使用Jasmin,您可以尝试Michael Falaga的方法

  function ajax_response(response) {
    var deferred = $.Deferred().resolve(response);
    return deferred.promise();
  }
Run Code Online (Sandbox Code Playgroud)

有了Jasmine

  describe("Test test", function() {
    beforeEach(function() {
      spyOn($, 'ajax').and.returnValue(
        ajax_response([1, 2, 3])
      );
    });
    it("is it [1, 2, 3]", function() {
      var response;
      $.ajax('GET', 'some/url/i/fancy').done(function(data) {
        response = data;
      });
      expect(response).toEqual([1, 2, 3]);
    });
  });
Run Code Online (Sandbox Code Playgroud)

没有茉莉花

  $.ajax = ajax_response([1, 2, 3]);
  $.ajax('GET', 'some/url/i/fancy').done(function(data) {
     console.log(data); // [1, 2, 3]
  });
Run Code Online (Sandbox Code Playgroud)


Stu*_*ser 14

在阅读了@Robusto和@Val的启发之后,我发现了一种有效的方法:

//Mock ajax function
$.ajax = function (param) {
    _mockAjaxOptions = param;
    //call success handler
    param.complete("data", "textStatus", "jqXHR");
};
Run Code Online (Sandbox Code Playgroud)

我没有从任何真正的$ .ajax代码中引发事件或触发任何事件,而是让我的假ajax对象调用函数(作为参数传入$.ajax())作为我的假函数的一部分.

  • 虽然可能会迟到,但您可能一直在寻找https://github.com/appendto/jquery-mockjax (2认同)
  • 那么,这个似乎悬而未决的_mockAjaxOptions`未声明变量到底怎么办? (2认同)

gfu*_*lam 11

使用闭包来覆盖$.ajax虚拟响应

在尝试了接受的答案user1634074发布的答案后,我设计了这两种简单灵活的混合方式.

最基本的形式......

function ajax_response(response) {
  return function (params) {
    params.success(response);
  };
}
$.ajax = ajax_response('{ "title": "My dummy JSON" }');
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,定义一个函数ajax_response(),该函数接受一些JSON字符串作为参数(或用于模拟响应的任意数量的自定义参数),并返回一个匿名闭包函数,该函数将被指定$.ajax为单元测试的覆盖.

匿名函数接受一个params参数,该参数将包含传递给$.ajax函数的设置对象.它使用传递给外部函数的参数来模拟来自服务器的响应.在此示例中,它始终通过简单地调用success回调并为其提供虚拟JSON 来模拟来自服务器的成功响应.

很容易重新配置......

function ajax_response(response, success) {
  return function (params) {
    if (success) {
      params.success(response);
    } else {
      params.error(response);
    }
  };
}

// Simulate success
$.ajax = ajax_response('{ "title": "My dummy JSON." }', true); 
doAsyncThing(); // Function that calls $.ajax

// Simulate error
$.ajax = ajax_response('{ "error": "Who is the dummy now?" }', false); 
doAsyncThing(); // Function that calls $.ajax
Run Code Online (Sandbox Code Playgroud)

下面我们可以看到它在行动......

/* FUNCTION THAT MAKES AJAX REQUEST */
function doAsyncThing() {
  $.ajax({
    type: "POST",
    url: "somefile.php",
    // data: {…},
    success: function (results) {
      var json = $.parseJSON(results),
          html = $('#ids').html();
      $('#ids').html(html + '<br />' + json.id);
    }
  });
}

/* BEGIN MOCK TEST */
// CREATE CLOSURE TO RETURN DUMMY FUNCTION AND FAKE RESPONSE
function ajax_response(response) {
  return function (params) {
    params.success(response);
  };
}

var n = prompt("Number of AJAX calls to make", 10);

for (var i = 1; i <= n; ++i) {
  
  // OVERRIDE $.ajax WITH DUMMY FUNCTION AND FAKE RESPONSE
  $.ajax = ajax_response('{ "id": ' + i + ' }');
  doAsyncThing();
}
/* END MOCK TEST */
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="ids">IDs:</p>
Run Code Online (Sandbox Code Playgroud)


Jas*_*ing 5

在不干扰 jQuery 的情况下根据需要模拟 $.ajax

这里的答案很好,但有一个特定的需求,即构建对单个 API 调用的虚假响应,同时让所有其他 API 调用保持不变,直到构建后端服务,以便我可以继续在 UI 上构建内容。

API 对象在幕后使用 $.ajax,因此您可以像这样调用 API 方法:

api.products({ price: { $lt: 150, tags: ['nike', 'shoes'] } })
.done(function(json) {
  // do something with the data
})
.error(function(err) {
  // handle error
});
Run Code Online (Sandbox Code Playgroud)

这种方法可以解决问题:

function mockAjax(options) {
  var that = {
    done: function done(callback) {
      if (options.success)
        setTimeout(callback, options.timeout, options.response);
      return that;
    },
    error: function error(callback) {
      if (!options.success)
        setTimeout(callback, options.timeout, options.response);
      return that;
    }
  };
  return that;
}
Run Code Online (Sandbox Code Playgroud)

然后在不触及 $.ajax 的情况下覆盖单个 api 调用:

api.products = function() {
  return mockAjax({
    success: true,
    timeout: 500,
    response: {
      results: [
        { upc: '123123', name: 'Jordans' },
        { upc: '4345345', name: 'Wind Walkers' }
      ]
    }
  });
};
Run Code Online (Sandbox Code Playgroud)

https://jsfiddle.net/Lsf3ezaz/2/