【问题标题】:Angular 1.1.5 test promise-based serviceAngular 1.1.5 测试基于承诺的服务
【发布时间】:2013-06-29 11:14:40
【问题描述】:

我们使用 karma 对我们的 Angular 服务进行单元测试,这些服务包含 $http 调用,因此我们有一个模拟的 $httpbackend,因此我们可以在没有服务器和数据库的情况下运行应用程序。 这工作正常,服务可以调用 $http("someurl?id=1234") 并且我们得到正确的数据。

但是当我们尝试在单元测试中做同样的事情时,我们无法让它工作,当涉及到 $http 时,promise 永远不会解决

服务:

getAllowedTypes: function (contentId) {
    var deferred = $q.defer();
    $http.get(getChildContentTypesUrl(contentId))
        .success(function (data, status, headers, config) {
            deferred.resolve(data);
        }).
        error(function (data, status, headers, config) {
            deferred.reject('Failed to retreive data for content id ' + contentId);
        });
    return deferred.promise;
}

模拟的 $httpbackend

$httpBackend
   .whenGET(mocksUtills.urlRegex('/someurl'))
   .respond(returnAllowedChildren); //returns a json object and httpstatus:200

测试

it('should return a allowed content type collection given a document id', function(){

    var collection;
    contentTypeResource.getAllowedTypes(1234).then(function(result){
        collection = result;
    });

    $rootScope.$digest();

    expect(collection.length).toBe(3);
});

但是集合是未定义的,.then() 永远不会被调用。

尝试了几乎所有方法来解决承诺,$rootScope.$apply()、$digest、$httpBacke.flush(),但没有任何效果

所以模拟 $httpBackend 在应用程序中从控制器调用时有效,但在 karma 单元测试中直接调用服务时无效

【问题讨论】:

    标签: angularjs karma-runner


    【解决方案1】:

    您不需要消化两次,因为 $httpBackend.flush() 会调用 digest 本身。 您必须进行调用,调用摘要以解析请求拦截器,调用刷新。

    这是一个有效的 Plnkr:http://plnkr.co/edit/FiYY1jT6dYrDhroRpFG1?p=preview

    【讨论】:

    【解决方案2】:

    在您的情况下,您必须 $digest 两次,一次用于 $httpBackend,另一次用于您自己的 deferred。

    所以:

    it('should return a allowed content type collection given a document id', function(){
    
        var collection;
        contentTypeResource.getAllowedTypes(1234).then(function(result){
            collection = result;
        });
        $httpBackend.flush();
        $rootScope.$digest();
    
        expect(collection.length).toBe(3);
    });
    

    【讨论】:

    • 已经尝试过 .flush(),但得到:“错误:没有挂起的刷新请求!”这似乎是自 1.1.4 以来的常见错误:github.com/angular/angular.js/issues/2431
    • 这里的顺序不对,需要先$digest再flush。
    【解决方案3】:

    你快到了。在您的情况下,您只需要在刷新 HTTP 后端之前强制执行摘要循环。请参阅下面的示例代码。

    it('should return a allowed content type collection given a document id', function(){
    
        var collection;
        contentTypeResource.getAllowedTypes(1234).then(function(result){
            collection = result;
        });
    
        $rootScope.$digest();
        $httpBackend.flush();
        expect(collection.length).toBe(3);
    });
    

    【讨论】:

    • 这是 .flush() 没有 .$flush() 顺便说一句,不,不工作,得到“没有挂起的刷新请求”错误,请参阅:github.com/angular/angular.js/issues/2431
    • $rootScope.$digest() 如果您单独测试服务,则不需要 IMO。
    猜你喜欢
    • 1970-01-01
    • 2016-02-18
    • 2015-08-12
    • 2017-08-02
    • 2017-03-01
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    相关资源
    最近更新 更多