正如@BrianDriscoll 评论的那样,您需要使用某种单元测试框架。那里有很多。
我也遇到了这个问题,我没有找到一个好的 JavaScript 的 AJAX 模拟框架。我最终创建了 Mocking Bird。
使用 MockingBird 模拟请求的优势
- 它让您可以精细控制 URL、HTTP 方法、状态、请求标头、响应标头和响应正文
- 很容易禁用所有本机 XMLHttpRequest 调用并插入支持相同接口的模拟对象,而无需更改被测代码
- 保持原生 XMLHttpRequest 启用很容易,但创建一个模拟请求并将其注入到测试方法中
- AJAX 变得同步,使单元测试更容易。
- MockingBird 可以与任何单元测试框架一起使用
- MockingBird 没有外部依赖项
缺点
- AJAX 变得同步。被测代码的行为可能会有所不同
- 目前无法测试连接超时
- 目前无法测试分块的 HTTP 响应
- 您实际上并未使用 Web 服务进行端到端测试,这将需要额外的集成测试(无论如何您都应该这样做)
- 使用 MockingBird 禁用网络连接后,任何 AJAX 请求都不会起作用。
- 它不强制执行相同的域策略。您可以模拟通过单元测试但在集成测试中引发错误的跨域 AJAX 调用。
一个快速而肮脏的例子:
var request = new MockingBird.XMLHttpRequest()
.returnsStatus(200)
.returnsBody('{"message":"I am a teapot"}')
.returnsHeaders({
"Content-Type": "text/json"
});
callSomeFunctionThatUsesAjax(request);
function callSomeFunctionThatUsesAjax(xhr) {
xhr.onreadystatechange = function() {
...
};
xhr.open("POST", "/foo");
xhr.send(null);
}
您还可以为无法提供自己的 AJAX 对象的情况设置模拟调用:
MockingBird.XMLHttpRequest.disableNetworkConnections()
.mock("/posts/123", "GET", {
status: 404,
body: "Page not found"
})
.mock("/posts/321/comments", "POST", {
status: 201,
responseHeaders: {
"Content-Type": "text/json"
},
body: {
post: {
id: 321,
comment: {
id: 1234
}
}
}
});
现在您直接实例化 XMLHttpRequest 对象的代码甚至不需要知道 MockingBird 的存在:
function createComment(postId, text) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState !== 4) return;
if (this.status === 201) {
var data = JSON.parse(this.responseText);
alert("Created comment: " + data.post.comment.id);
}
else if (this.status === 404) {
alert("Post " + postId + " not found!");
}
};
xhr.open("POST", "/posts/" + postId);
xhr.send("post[id]=" + postId + "&post[comment][text]=" + escape(text));
}
createComment(123, "Test Test"); // alert's "Post 123 not found!"
createComment(321, "Test Test"); // alert's "Created comment: 1234"