Jasmine,使用 Promises 对 XMLHttpRequest 进行单元测试

Jasmine, Unit testing XMLHttpRequest with Promises

我有以下函数,它使用 Q promise 库

getConfig: function(params){

            return this.codeApiClient.get(this.endpoints.config, params, {}).then(function(response){
                return response;
            }, function(err){
                throw err;
            });
        }

上面的代码调用了下面显示的 API 代码(我已经缩写了代码以消除噪音)

CodeApiClient.prototype = {
  get: function(endpoint, paramStr, headers){
      var defer = new Q.defer();
      var start_time = new Date().getTime();

      var req = new XMLHttpRequest();
      var url = endpoint + (paramStr.indexOf('?') !== -1 ? paramStr : '?' + paramStr);

      req.open('GET', url);

      req.onload = function() {
          var request_time = new Date().getTime() - start_time;
          // This is called even on 404 etc
          if (req.status < 400) {
              var response = JSON.parse(req.response)
              response.__request_time = request_time;
              defer.resolve(response);
          } else {
              // Otherwise reject with the status text
              defer.reject(Error(req.statusText));
          }
      };
}

我的问题是:如何为 getConfig 编写 Jasmine 测试,即伪造响应并存根底层 XMLHttpRequest ? sinon.js 有这个能力吗?我知道它可以在 $.ajax 上存根回调,但我不确定如何使用诸如 Q 之类的承诺库来执行此操作。注意这是纯 JavaScript,没有 angular 等

  • 以下是如何在 jasmine 中使用 callFake 来 return 承诺。
  • 现在由于 Q 和传统 jQuery 都提供延迟 对象,您可以将 $.Deferred() 替换为 Q.defer();

var tempObj = {
     getConfig: function(params){

                return this.codeApiClient.get(this.endpoints.config, params, {}).then(function(response){
                    return response;
                }, function(err){
                    throw err;
                });
            }
        codeApiClient : {
          get : function(){
            // some get function of codeApiClient
          }
        }
    }


    it('test getConfig success', function(){
     var dummyResponse = {'someDummyKey' : 'someDummyValue'};
     spyOn(tempObj.codeApiClient, 'get').and.callFake(function(e){
      return $.Deferred().resolve(dummyResponse).promise();
     }); 
      tempObj.getConfig({});
      //any expectations
    });

    it('test getConfig failure', function(){
     var dummyResponse = {'error' : 'someDummyFailure'};
     spyOn(tempObj.codeApiClient, 'get').and.callFake(function(e){
      return $.Deferred().reject(dummyResponse).promise();
     });
       tempObj.getConfig({});
      //any expectations
    });

如果有人感兴趣,这是我的 Jasmine 测试,希望对您有所帮助

define([ 'q', 'lodash', 'jquery',  'ChatApi'], function (Q, _ , $ ,  ChatApi) {

    describe('Chat Api test', function () {
        var categories
        var chatApi;
        var fakeResponse;

        beforeEach(function() {
            //fakes
             categories = {
                "l10n": {
                    "defaultLanguage": "en-GB",
                    "languages": [
                        {
                            "name": "en-GB",
                            "value": "Tell me more..."
                        },
                        {
                            "name": "fr",
                            "value": "On veut tout savoir..."
                        },
                        {
                            "name": "de",
                            "value": "Wähle die passende Kategorie aus..."
                        }
                    ]
                }
            };
            fakeResponse = {
                'categories': categories
            }
            chatApi = new ChatApi("https://server/gateway/","v1");
        });

        it('test getConfig success', function(done){
            var getConfigCalled = spyOn(chatApi, 'getConfig').and.callFake(function(e){
                //jQuery version of promises
               //return $.Deferred().resolve(fakeResponse).promise();
                var deferred = Q.defer();
                deferred.resolve(fakeResponse);
                return deferred.promise;
            });

            chatApi.getConfig({}).then(function(response){
                //compare objects using lodash
                var x = _.isEqual(response.categories, fakeResponse.categories);
                expect(x).toBe(true);
            })

            expect(getConfigCalled).toHaveBeenCalled();

            done();
        });

    });
});