如何用 Jasmine 验证 jQuery AJAX 事件?

我正在尝试使用 Jasmine 为基本的 jQueryAJAX 请求编写一些 BDD 规范。我目前在独立模式下使用 Jasmine (即通过 SpecRunner.html)。我已经将 SpecRunner 配置为加载 jquery 和 other。JS 文件。知道为什么下面的方法行不通吗?已经返回并不成为真实的,甚至认为“ 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 的博客/资料,我将不胜感激。

61061 次浏览

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

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

Then it lets you provide fixture responses for all your cases and then write tests for each response that you want: success, failure, unauthorized, etc.

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

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

下面是我最近列举的一个例子:

Https://gist.github.com/946704

我想你可以做两种测试:

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

茉莉可以帮你做这两种检查。

Here is a sample of how you can fake the AJAX request, and then write a unit test to verify that the faked AJAX request was going to the correct 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 的异步特性来完成: wait ()、 waitsFor ()和 run () :

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

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

下面是一个简单的示例测试套件 for an app js like this

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

我觉得我需要提供一个更新的答案,因为 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
});
});
});

I've done the trick for the success function as well as the error function to make sure that Jasmine will run the specs as soon as possible even if your AJAX returns an error.

如果您没有指定一个错误函数,而您的 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