如何使用$ httpBackend对angularjs promise链进行单元测试

 飞逝舞_975 发布于 2023-02-12 15:24

使用AngularJS,我试图对一个多次调用$ http的函数进行单元测试.

我的测试看起来像这样:

it('traverses over a hierarchical structure over multiple chained calls', function() {

    myService.traverseTheStuff()
    .then(function(theAggregateResult) {
        // ...is never fulfilled
    });

    $httpBackend.flush();
});

其他单调用测试将注册传递给.then()的回调,并在我调用.flush()后立即执行.

测试中的代码看起来像这样.

function traverseTheStuff(){

    // This will make a call to $http to fetch some data
    return getRootData()

    // It is fulfilled at the end of the test when I $httpBackend.flush()
    .then(function(rootData){

        // Another call to $http happens AFTER $httpBackend.flush()
        return getNextLevel(rootData.someReference);
    })

    // The second promise is never fulfilled and the test fails
    .then(function(nextLevel){
        return aggregateTheStuff(...);
    });
}

值得一提的是,每个单独的呼叫都是单独测试的.在这里,我想遍历一棵树,聚合一些数据和单元测试a)承诺链正确连接和b)聚合是准确的.将其展平为单独的离散调用已经完成.

1 个回答
  • 我是测试Angular的初学者,但是我已经设置了一个plnkr,用一个成功的"秒"然后/保证调用来测试与你的设置非常相似的设置

    http://plnkr.co/edit/kcgWTsawJ36gFzD3CbcW?p=preview

    以下代码片段是上述plnkr的略微简化版本.

    我发现的关键点是

    我注意到函数traverseTheStuff根本没有调用$ http/$ httpBackend.它只使用$ q promises中定义的函数,因此测试假设使用$ q,并注入它

    var deferred1 = null;
    var deferred2 = null;
    var $q = null;
    
    beforeEach(function() {
      inject(function(_$q_) {
        $q = _$q_;
      });
    });
    
    beforeEach(function() {
      deferred1 = $q.defer();
      deferred2 = $q.defer();
    }
    

    异步调用的函数使用其promise返回值进行间谍/存根,其中promise在测试本身中创建,因此在测试traverseTheStuff时不会调用它们的实际实现

    spyOn(MyService,'traverseTheStuff').andCallThrough();
    spyOn(MyService,'getRootData').andReturn(deferred1.promise);
    spyOn(MyService,'getNextLevel').andReturn(deferred2.promise);
    spyOn(MyService,'aggregateTheStuff');
    

    在测试中没有任何"then"的调用,只是为了"解析"测试中创建的promise,然后是$ rootScope.$ apply(),然后实际调用traverseTheStuff中的"then"回调,我们也可以测试一下

    beforeEach(function() {
      spyOn(deferred1.promise, 'then').andCallThrough();
    });
    
    beforeEach(function() {
      deferred1.resolve(testData);
      $rootScope.$apply(); // Forces $q.promise then callbacks to be called
    });
    
    it('should call the then function of the promise1', function () { 
      expect(deferred1.promise.then).toHaveBeenCalled();
    });
    

    必须解决每个承诺/ $ apply-ed以调用链中的下一个"then"函数.所以.要获得测试调用aggregateTheStuff(或者更确切地说,它的存根),还必须解析从getNextLevel存根返回的第二个promise:

    beforeEach(function() {
      deferred2.resolve(testLevel);
      $rootScope.$apply(); // Forces $q.promise then callbacks to be called
    });
    
    it('should call aggregateTheStuff with ' + testLevel, function () {
      expect(MyService.aggregateTheStuff).toHaveBeenCalledWith(testLevel);
    });
    

    上述所有问题都是它假定来自$ q和$ rootScope的某些行为.我是在理解单元测试这样的假设不应该做出这样的假设,以便真正只测试一点代码.我没有弄清楚如何解决这个问题,或者我是否误解了.

    2023-02-12 15:26 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有