【问题标题】:Jasmine test for an ajax request that returns a promiseJasmine 测试返回承诺的 ajax 请求
【发布时间】:2014-10-31 18:07:19
【问题描述】:

我是 Angular 测试的新手。

我正在尝试在服务中测试一个简单的方法,该方法通过 ajax 调用获取一些数据并使用 Jasmine 返回一个承诺。

到目前为止非常不成功。

这是我正在测试的方法:

function getDefaultFibonnacci() {
        var deferred = $q.defer();

        $http({ method: 'GET', url: '/api/fibonnacci/get' })
            .success(function (data) {
                deferred.resolve(data);
            })
            .error(function (data, status) {
                deferred.reject(status);
            });

        return deferred.promise;
    }

这是我的测试代码:(请注意除了“应该返回 0,1,1,2,3”之外的所有其他测试都通过

describe('datacontext', function () {
    var $httpBackend;
    var $rootScope;
    var datacontext;
    var $q;

    beforeEach(function () {
        module('app');
        inject(function (_$httpBackend_, _$rootScope_, _$q_, _datacontext_) {
            $httpBackend = _$httpBackend_;
            $rootScope = _$rootScope_;
            datacontext = _datacontext_;
            $q = _$q_;
        });
    });

    it('should have a getDefaultFibonnacci() function', function () {
        expect(angular.isFunction(datacontext.getDefaultFibonnacci)).toBe(true);
    });

    it('should return a promise', function () {
        expect(datacontext.getDefaultFibonnacci().then).toBeDefined();
    });

    it('should return 0,1,1,2,3', function () {
        var sequence = '123';

        $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
        $httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

        var deferred = $q.defer();
        var promise = deferred.promise;

        promise.then(function (response) {
            sequence = response.success;
        });

        datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });

        $rootScope.$digest();

        expect(sequence).toEqual('0,1,1,2,3');
    });
});

各位,感谢你们所有的 cmets。通过这次练习,我学到了很多东西。

这是我最终通过测试的代码。

function getDefaultFibonnacci() {
        return $http({ method: 'GET', url: '/api/fibonnacci/get' });
    }

it('should return 0,1,1,2,3', function () {
        var sequence;

        $httpBackend.whenGET('app/dashboard/dashboard.html').respond('');

        $httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');

        datacontext.getDefaultFibonnacci().then(function (data) {
            sequence = data.data;
        });

        $httpBackend.flush();

        expect(sequence).toEqual('0,1,1,2,3');
    });

【问题讨论】:

  • 请考虑阅读有关延迟反模式的信息 - 您的代码比应有的复杂得多,并且可以大大简化。您的代码中实际上不需要延迟。
  • 摩卡是一种选择吗?在测试 Promise 方面,它的语法比 Jasmine 更好。

标签: angularjs jasmine promise


【解决方案1】:

$httpBackend 有一个 flush() 方法正是出于这个原因。

flush()模拟http服务器响应,所以会触发你$http.get()的解析。在您致电flush() 之前,什么都不会发生(服务器尚未响应)。

因此,将您的 $rootScope.digest() 代码替换为 $httpBackend.flush() 并从那里开始工作。

此外,您可以通过了解$http 方法本身返回承诺来节省大量精力。

这个:

function getDefaultFibonnacci() {
    var deferred = $q.defer();

    $http({ method: 'GET', url: '/api/fibonnacci/get' })
        .success(function (data) {
            deferred.resolve(data);
        })
        .error(function (data, status) {
            deferred.reject(status);
        });

    return deferred.promise;
}

可以简化为:

function getDefaultFibonnacci() {

    return $http({ method: 'GET', url: '/api/fibonnacci/get' })

}

并且会做同样的事情。

最后,您的测试中不需要另一个承诺。这已经足够了(删除所有对$q 的引用并推迟并将其直接放在您的$httpBackend.when(... 代码之后):

datacontext.getDefaultFibonnacci()
.then(function (data) { 
    sequence = data;
});

【讨论】:

  • 感谢您的反馈。我仍然对 Angular/JS 感兴趣。我不知道 $http 返回一个承诺。按照您的建议更改代码会导致数据成为 json blob,其中包含一个名为 data 的属性,其中包含我的字符串。这是您的预期还是我错过了什么?
  • @Jemmitch 这是预期的 - 如果你明确想要它,你可以这样做:return $http(...).then(function(response){ return response.data; })
  • 更改为这种模式。我将对 $http 进行一些调查(有人建议我切换到 restangular),因为它缺乏错误处理。
【解决方案2】:

您是否期望一个对象 {success: "0,1,1,2,3"} 作为来自 http 服务的响应?当承诺解决时,你正在使用response.success

promise.then(function (response) {
            sequence = response.success;
        });

而您返回的是字符串 '0,1,1,2,3'

$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

另外,从代码中我看到您不需要创建另一个承诺来测试您的方法。

试试这个:

it('should return 0,1,1,2,3', function () {
        var sequence = '123';

        $httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
        $httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');

        datacontext.getDefaultFibonnacci().then(function (data) { sequence = data; });

        $rootScope.$digest();

        expect(sequence).toEqual('0,1,1,2,3');
    });

【讨论】:

  • 即使你打电话给$rootScope.$digest,如果立即初始化序列,我也会感到惊讶。如果是这样 - 这绝对是一个错误。你能创建一个小提琴来说明这种行为吗?
  • 你的意思是它应该使用 $httpBacked.flush() 而不是 $rootScope.$digest() 或者它不是 $rootScope.$digest() 的预期行为来解决一个承诺?
  • 即使是已解决的 Promise 也会推迟到下一个周期执行。这是 Promises/A+ 规范的一部分,测试应该是异步的。
  • Response.Success 是一个错误,我将其更改为仅查看响应。我得到了测试工作(我在 httpbackend 上添加了刷新并将 response.success 更改为响应)但显然我过于复杂了这个代码/测试,所以我正在根据评论进行重构。
  • @BenjaminGruenbaum,因此,即使在单元测试中,也应该始终异步地检查承诺是否已解决?
【解决方案3】:

您忘记做的最重要的事情是在发出请求后的某个时间点调用$httpBackend.flush(),然后再使用数据。

您也不需要创建额外的承诺。

it('should return 0,1,1,2,3', function () {
    var sequence;

    // Use the shorthand method whenGET
    $httpBackend.whenGET('app/dashboard/dashboard.html').respond('');

    // We should probably test that this request is actually made, so use expect<method>
    $httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');

    // Leave out the extra promise code.
    // var deferred = $q.defer();
    // var promise = deferred.promise;

    // promise.then(function (response) {
    //     sequence = response.success;
    // });

    // datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });

    datacontext.getDefaultFibonnacci().then(function (response) {
        sequence = response.success;
    });

    $httpBackend.flush(); // Flush the backend. Important!
    // $rootScope.$digest(); // I don't think this is necessary.

    expect(sequence).toEqual('0,1,1,2,3');
});

如果您设置了应用程序,则不会调用 html 模板

【讨论】:

    猜你喜欢
    • 2017-04-07
    • 1970-01-01
    • 2020-07-30
    • 2016-06-17
    • 2014-05-19
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    相关资源
    最近更新 更多