用Jasmine模拟jQueryAjax调用

用Jasmine模拟jQueryAjax调用,jquery,ajax,unit-testing,jasmine,jasmine-ajax,Jquery,Ajax,Unit Testing,Jasmine,Jasmine Ajax,我使用Jasmine 2.5.2为使用jQuery3.1.1执行Ajax请求的代码编写单元测试。我想模拟Ajax调用,提供我自己的响应状态和文本 我正在使用jasmineajax插件() 遵循上的示例,它使用XMLHttpRequest对象,效果很好 describe("mocking ajax", function() { describe("suite wide usage", function() { beforeEach(function() {

我使用Jasmine 2.5.2为使用jQuery3.1.1执行Ajax请求的代码编写单元测试。我想模拟Ajax调用,提供我自己的响应状态和文本

我正在使用jasmineajax插件()

遵循上的示例,它使用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()

当我使用jQueryAjax时,从不调用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 Ajax在 XMLHttpRequest对象,因此应与其他 执行ajax请求的库


$.ajax从1.4.x返回一个jqXHR,而不是XMLHttpRequest-这会破坏Jasmine ajax的支持吗?

以下是在Jasmine测试中模拟ajax的几种方法

方法A:

  • 使用mock ajax.js,可以模拟全局xhr对象,如中所述
  • 但是,您需要在success函数上指定一个spy,并让它调用(如下面的代码所示)
  • 看到它在行动吗

方法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'});
      });
    });
    

模拟$.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);
});
除回答(方法B)外:

我添加了
options.success(testData)
inside
spyOn($,'ajax')
来触发
this.processResponseData

Fn测试:

 var objUnderTest = {};
 objUnderTest.makeRequest(requestUrl) {
    $.ajax(requestUrl)
      .then(response => {
        this.processResponseData(response.data[0]) // get data from first array item
      })
  }
测试:


你的第二种方法在这里对我有效。假代码还可以返回
$.Deferred().reject(obj)
来测试Ajax错误,其中obj有一个带有错误文本的responseText属性。@Lozzer这是正确的。使用deferred,您可以根据您的需求来解决/拒绝。如果我们有其他jQuery AJAX调用需要在测试中调用,该怎么办?我开始觉得这是唯一可行的解决方案,我对此一点也不高兴。如果我只是想模拟整个$.ajax函数,那么首先使用jasmine.ajax有什么意义呢?在第二个示例中,您从来没有为请求定义响应。。。
 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();
    });
  });