我们正在尝试为JS重型Web应用程序实施QUnit JavaScript测试。我们正在努力寻找成功测试涉及jQuery AJAX请求的方法的方法。例如,我们有以下构造函数(显然这是一个非常简单的例子):
var X = function() {
this.fire = function() {
$.ajax("someURL.php", {
data: {
userId: "james"
},
dataType: "json",
success: function(data) {
//Do stuff
}
});
};
};
var myX = new X();
myX.fire();
我们正在尝试找到一种方法来测试fire
方法,最好使用存根网址而不是真实的someURL.php
。
目前唯一明显的解决方案是将URL和success
回调添加为构造函数的参数。这样,在测试中,我们可以创建X
的新实例并传入存根URL,并在存根返回响应时运行回调。例如:
test("Test AJAX function", function() {
stop();
var myX = new X();
//Call the AJAX function, passing in the stub URL and success callback
myX.fire("stub.php", function(data) {
console.log(data);
start();
});
});
然而,这似乎不是一个非常好的解决方案。还有更好的方法吗?
答案 0 :(得分:9)
使用jQuery,您可以使用.ajax()
作为承诺返回的xhr对象,因此您可以添加更多处理程序(请参阅下文),而不仅仅是单success
,complete
和{ {1}}您在选项中定义的内容。因此,如果异步函数可以返回xhr对象,则可以添加特定于测试的处理程序。
至于URL,这有点棘手。我有时在localhost上设置一个非常简单的节点服务器,它只提供从真实服务器复制的预设响应。如果您在相同的服务器上运行测试套件,则您的URL只需要是命中测试服务器而不是生产服务器的绝对路径。当服务器看到它们时,您还会获得请求本身的记录。或者,如果您想查看代码如何处理它,您可以让测试服务器故意发回错误或错误响应。
但这当然是一个非常复杂的解决方案。更容易的是在您可以从测试套件重新定义URL的位置定义URL。例如:
error
此外,QUnit还有一个/* in your code */
var X = function () {
this.fire = function () {
return $.ajax({ url: this.constructor.url, ... });
};
};
X.url = "someURL.php"; // the production url
/* in your tests */
X.url = "stub.php"; // redefine to the test url
功能,可以为您调用asyncTest
。添加一个小帮手来跟踪何时重新开始,你有一个很好的解决方案。
这是我之前做过的事情
stop()
基本上// create a function that counts down to `start()`
function createAsyncCounter(count) {
count = count || 1; // count defaults to 1
return function () { --count || start(); };
}
// ....
// an async test that expects 2 assertions
asyncTest("testing something asynchronous", 2, function() {
var countDown = createAsyncCounter(1), // the number of async calls in this test
x = new X;
// A `done` callback is the same as adding a `success` handler
// in the ajax options. It's called after the "real" success handler.
// I'm assuming here, that `fire()` returns the xhr object
x.fire().done(function(data, status, jqXHR) {
ok(data.ok);
equal(data.value, "foobar");
}).always(countDown); // call `countDown` regardless of success/error
});
是一个从您指定的任何内容倒计数到零的函数,然后调用countDown
。在这种情况下,有1个异步调用,因此start()
将从中倒数。当ajax调用结束时,无论它如何运行,它都会这样做,因为它被设置为countDown
回调。
并且因为always
被告知期望2个断言,如果永远不会调用asyncTest
回调,它将报告错误,因为不会运行断言。因此,如果通话完全失败,您也会知道。如果您想记录错误的内容,可以在promise链中添加.done()
回调。
答案 1 :(得分:3)
如果它是可以(并且应该)与服务器端隔离运行的单元测试,则可以简单地“替换”$.ajax
来模拟任何行为。
一个简单的例子:
test("Test AJAX function", function() {
// keep the real $.ajax
var _real_ajax = $.ajax;
// Simulate a successful response
$.ajax = function(url, opts) {
opts.success({expected: 'response'});
}
var myX = new X();
// Call your ajax function
myX.fire();
// ... and perform your tests
// Don't forgot to restore $.ajax!
$.ajax = _real_ajax;
});
显然你也可以使用存根url / data执行真正的ajax调用:
// Simulate a successfully response
$.ajax = function(url, opts) {
opts.success = function(data) {
console.log(data);
start();
}
_real_ajax('stub.php', opts)
}
如果您没有复杂的回答,我更喜欢第一种方法,因为它更快更容易理解 但是,您也可以采用另一种方式将Ajax逻辑放在自己的方法中,这样您就可以在测试期间轻松将其存根。
答案 2 :(得分:2)
尝试使用jQuery spy
。我已经创建了一种更简单的方法来使用jQuery熟悉的语法来测试ajax。