用 Jasmine 模拟 jQuery ajax 调用
Mocking jQuery ajax calls with Jasmine
我正在使用 Jasmine 2.5.2 为使用 jQuery 3.1.1 执行 Ajax 请求的代码编写单元测试。我想模拟 Ajax 调用,提供我自己的响应状态和文本。
我正在使用 Jasmine ajax 插件 (https://github.com/pivotal/jasmine-ajax)。
按照 https://jasmine.github.io/2.0/ajax.html 上的示例,它使用 XMLHttpRequest 对象,效果很好。
describe("mocking ajax", function() {
describe("suite wide usage", function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it("specifying response when you need it", function() {
var doneFn = jasmine.createSpy("success");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(args) {
if (this.readyState == this.DONE) {
doneFn(this.responseText);
}
};
xhr.open("GET", "/some/cool/url");
xhr.send();
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
expect(doneFn).not.toHaveBeenCalled();
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"contentType": 'text/plain',
"responseText": 'awesome response'
});
expect(doneFn).toHaveBeenCalledWith('awesome response');
});
});
});
注意:这与记录的示例略有不同,必须将 jasmine.Ajax.requests.mostRecent().response()
更改为 jasmine.Ajax.requests.mostRecent().respondWith()
。
当我使用 jQuery Ajax 时,永远不会调用 doneFn。
describe("mocking ajax", function() {
describe("suite wide usage", function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it("specifying response when you need it", function() {
var doneFn = jasmine.createSpy("success");
$.ajax({
method: "GET",
url: "/some/cool/url"})
.done(function(result) {
doneFn(result);
});
expect(doneFn).toHaveBeenCalledWith('awesome response');
});
});
});
Jasmine 说
Jasmine-Ajax mocks out your request at
the XMLHttpRequest object, so should be compatible with other
libraries that do ajax requests.
$.ajax returns 来自 1.4.x 而不是 XMLHttpRequest 的 jqXHR - 这会破坏对 Jasmine Ajax 的支持吗?
您可以通过以下几种方式在 jasmine 测试中模拟 ajax
方法一:
- 使用 mock ajax.js,您可以 mock 全局 xhr 对象,如 doc
中所述
- 但是,您需要在 success 函数上指定一个 spy 并让它 callThrough(如下面的代码所示)
查看实际效果here
describe('ajax test suite', function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it('sample test', function() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(args) {
if (this.readyState == this.DONE) {
testObj.successFunction(this.responseText);
}
};
spyOn(testObj, 'successFunction').and.callThrough();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1");
xhr.send();
expect(jasmine.Ajax.requests.mostRecent().url).toBe('https://jsonplaceholder.typicode.com/posts/1');
expect(testObj.successFunction).not.toHaveBeenCalled();
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"contentType": 'text/plain',
"responseText": 'awesome response'
});
expect(testObj.successFunction).toHaveBeenCalledWith('awesome response');
});
});
方法 B:
直接模拟 $.ajax 对象。无论是 get/post/load 还是来自 jquery 的任何 ajax 风格,您都可以简单地模拟 $.ajax,如下所示。
var testObj = {
ajaxFunction : function(url){
$.ajax({url : url}).done(this.successFunction.bind(this));
},
successFunction : function(data){
console.log(data);
}
}
describe('ajax test suite', function(){
it('sample test', function(){
testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1');
spyOn($, 'ajax').and.callFake(function(e) {
return $.Deferred().resolve({'text':'this a a fake response'}).promise();
});
spyOn(testObj, 'successFunction').and.callThrough();
testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1');
expect(testObj.successFunction).toHaveBeenCalledWith({'text':'this a a fake response'});
});
});
mock $.ajax对象时,可以直接使用传入的参数触发成功或失败,无需经过promise接口
spyOn($, 'ajax').and.callFake(function (options) {
var result = undefined, status, xhr;
options.success(result, status, xhr);
});
spyOn($, 'ajax').and.callFake(function (options) {
var xhr = undefined, status, error;
options.error(xhr, status, error);
});
除了danronmoon答案(方法B):
我在spyOn($, 'ajax')
里面添加了options.success(testData)
来触发this.processResponseData
Fn 测试:
var objUnderTest = {};
objUnderTest.makeRequest(requestUrl) {
$.ajax(requestUrl)
.then(response => {
this.processResponseData(response.data[0]) // get data from first array item
})
}
测试:
describe('objUnderTest.makeRequest', () => {
const testData = {data: [{'text': 'this a a fake response'}]};
let processResponseData;
beforeAll(() => {
spyOn($, 'ajax').and.callFake(function (options) {
options.success(testData)
return $.Deferred().resolve(testData).promise();
});
processResponseData = spyOn(objUnderTest, 'processResponseData')
})
it('should make ajax call', () => {
objUnderTest.makeRequest({success: stockTicker.processResponseData});
expect(processResponseData).toHaveBeenCalled();
});
});
我正在使用 Jasmine 2.5.2 为使用 jQuery 3.1.1 执行 Ajax 请求的代码编写单元测试。我想模拟 Ajax 调用,提供我自己的响应状态和文本。
我正在使用 Jasmine ajax 插件 (https://github.com/pivotal/jasmine-ajax)。
按照 https://jasmine.github.io/2.0/ajax.html 上的示例,它使用 XMLHttpRequest 对象,效果很好。
describe("mocking ajax", function() {
describe("suite wide usage", function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it("specifying response when you need it", function() {
var doneFn = jasmine.createSpy("success");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(args) {
if (this.readyState == this.DONE) {
doneFn(this.responseText);
}
};
xhr.open("GET", "/some/cool/url");
xhr.send();
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
expect(doneFn).not.toHaveBeenCalled();
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"contentType": 'text/plain',
"responseText": 'awesome response'
});
expect(doneFn).toHaveBeenCalledWith('awesome response');
});
});
});
注意:这与记录的示例略有不同,必须将 jasmine.Ajax.requests.mostRecent().response()
更改为 jasmine.Ajax.requests.mostRecent().respondWith()
。
当我使用 jQuery Ajax 时,永远不会调用 doneFn。
describe("mocking ajax", function() {
describe("suite wide usage", function() {
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it("specifying response when you need it", function() {
var doneFn = jasmine.createSpy("success");
$.ajax({
method: "GET",
url: "/some/cool/url"})
.done(function(result) {
doneFn(result);
});
expect(doneFn).toHaveBeenCalledWith('awesome response');
});
});
});
Jasmine 说
Jasmine-Ajax mocks out your request at the XMLHttpRequest object, so should be compatible with other libraries that do ajax requests.
$.ajax returns 来自 1.4.x 而不是 XMLHttpRequest 的 jqXHR - 这会破坏对 Jasmine Ajax 的支持吗?
您可以通过以下几种方式在 jasmine 测试中模拟 ajax
方法一:
- 使用 mock ajax.js,您可以 mock 全局 xhr 对象,如 doc 中所述
- 但是,您需要在 success 函数上指定一个 spy 并让它 callThrough(如下面的代码所示)
查看实际效果here
describe('ajax test suite', function() { beforeEach(function() { jasmine.Ajax.install(); }); afterEach(function() { jasmine.Ajax.uninstall(); }); it('sample test', function() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(args) { if (this.readyState == this.DONE) { testObj.successFunction(this.responseText); } }; spyOn(testObj, 'successFunction').and.callThrough(); xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1"); xhr.send(); expect(jasmine.Ajax.requests.mostRecent().url).toBe('https://jsonplaceholder.typicode.com/posts/1'); expect(testObj.successFunction).not.toHaveBeenCalled(); jasmine.Ajax.requests.mostRecent().respondWith({ "status": 200, "contentType": 'text/plain', "responseText": 'awesome response' }); expect(testObj.successFunction).toHaveBeenCalledWith('awesome response'); }); });
方法 B:
直接模拟 $.ajax 对象。无论是 get/post/load 还是来自 jquery 的任何 ajax 风格,您都可以简单地模拟 $.ajax,如下所示。
var testObj = { ajaxFunction : function(url){ $.ajax({url : url}).done(this.successFunction.bind(this)); }, successFunction : function(data){ console.log(data); } } describe('ajax test suite', function(){ it('sample test', function(){ testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); spyOn($, 'ajax').and.callFake(function(e) { return $.Deferred().resolve({'text':'this a a fake response'}).promise(); }); spyOn(testObj, 'successFunction').and.callThrough(); testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); expect(testObj.successFunction).toHaveBeenCalledWith({'text':'this a a fake response'}); }); });
mock $.ajax对象时,可以直接使用传入的参数触发成功或失败,无需经过promise接口
spyOn($, 'ajax').and.callFake(function (options) {
var result = undefined, status, xhr;
options.success(result, status, xhr);
});
spyOn($, 'ajax').and.callFake(function (options) {
var xhr = undefined, status, error;
options.error(xhr, status, error);
});
除了danronmoon答案(方法B):
我在spyOn($, 'ajax')
里面添加了options.success(testData)
来触发this.processResponseData
Fn 测试:
var objUnderTest = {};
objUnderTest.makeRequest(requestUrl) {
$.ajax(requestUrl)
.then(response => {
this.processResponseData(response.data[0]) // get data from first array item
})
}
测试:
describe('objUnderTest.makeRequest', () => {
const testData = {data: [{'text': 'this a a fake response'}]};
let processResponseData;
beforeAll(() => {
spyOn($, 'ajax').and.callFake(function (options) {
options.success(testData)
return $.Deferred().resolve(testData).promise();
});
processResponseData = spyOn(objUnderTest, 'processResponseData')
})
it('should make ajax call', () => {
objUnderTest.makeRequest({success: stockTicker.processResponseData});
expect(processResponseData).toHaveBeenCalled();
});
});