使用Jasmine模拟jQuery ajax调用

我正在使用Jasmine 2.5.2为使用jQuery 3.1.1执行Ajax请求的代码编写unit testing。 我想模拟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在XMLHttpRequest对象上模拟您的请求,因此应该与执行ajax请求的其他库兼容。

$ .ajax从1.4.x返回jqXHR而不是XMLHttpRequest – 这是否会破坏对Jasmine Ajax的支持?

您可以通过以下几种方式在茉莉花测试中模拟ajax

方法A:

  • 使用mock ajax.js,您可以按照doc中的描述模拟全局xhr对象
  • 但是你需要在success函数上指定一个间谍并让它调用Thhrough(如下面的代码所示)
  • 在这里看到它

     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 aa fake response'}).promise(); }); spyOn(testObj, 'successFunction').and.callThrough(); testObj.ajaxFunction('https://jsonplaceholder.typicode.com/posts/1'); expect(testObj.successFunction).toHaveBeenCalledWith({'text':'this aa fake response'}); }); }); 

模拟$ .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); });