Jasmine不会测试具有多个嵌套承诺的角度服务

时间:2015-06-29 20:19:56

标签: angularjs jasmine karma-jasmine

我试图为角度服务编写一个jasmine测试用例。因为我必须调用PouchDB并获取http资源,所以我使用$ q。

在我的应用程序中,我有两个数据源:PouchDB作为localStorage和一个通过http请求的XML文档。我设法为localStorage.service和XMLparser.service编写测试,没有太多麻烦(我必须执行50ms超时然后调用$ rootScopre。$ digest())。

但是,当我尝试为使用localStorage和XMLParser的服务运行测试时,我无法通过它。 Karma挂起5秒,测试在超时时失败。如果我在任何地方添加一些console.log(),所有代码都会被执行。就像done()没有关闭测试用例一样。如果我直接在我的应用程序中运行代码,它就可以工作。

我的代码中有很多内容,所以我会尝试解释:

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

    //Json structure that tells my parser what to extract from the XML
    var structure = { ... } 

    //Check in the PouchDB to see if the structure is already cached
    localStorage.getStructure() 
    .then(function(struct){
        deferred.resolve(struct.category);
    })
    .catch(function(e){
        if(e.name != 'not_found') return deferred.reject(e);

        //If the structure is not cached, get it from the parser through an http request
        xmlparser.readFile(apiUrl, structure) 
        .then(function(doc){
            localStorage.saveStructure(doc); //Save it in the PouchDB
            deferred.resolve(doc.category); //Resolve with the categories
        })
        .catch(function(e){
            deferred.reject(e);
        });
    });

    return deferred.promise;
}

以下是我如何测试它:

it('should list the categories', function(done){
    //The answer to this call is mocked in the beforeEach
    $httpBackend.expectGET('/lib/xmlDocuments/indicator.xml');

    var promise = Indicator.getCategories()
    .then(function(categories){
        expect(categories[0].name).toBe('Emplois par secteur d\'activité');
        expect(categories[1].name).toBe('Emplois par niveau de compétence');
        done();
        //When i put a console.log here it get executed...
    })
    .catch(function(e){
        expect(e).toBe(null);
    });

    //Here i tryed to force a $digest and then flush() the requests
    //but i still get "Async callback was not invoked within timeout"
    setTimeout(function() {
        $scope.$digest();
        setTimeout(function(){
            $httpBackend.flush();
        }, 50);
    }, 50);
});

现在我非常确定我做得不好但我不能指责它:

  • 我是否错过了这些承诺?
  • 我应该模拟XMLParser和localStorage吗?
  • 我的茉莉花有错误吗?
  • 我过度使用$ q?

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

好吧,我最终嘲笑XMLParser和localStorage。我得出的结论是,重新测试这些服务是没有意义的。这是一个单元测试,应该只测试一个单元。

我还根据Explosion Pills的建议修改了对promises的使用。

//Load the categories
function loadCategories(){
    var structure = { ... }

    return localStorage.getStructure()
    .then(function(struct){
        return struct.category;
    })
    .catch(function(e){
        if(e.name != 'not_found') return e;

        return xmlparser.readFile(apiUrl, structure)
        .then(function(doc){
            localStorage.saveStructure(doc);
            return doc.category;
        });
    });
}

我在之前添加了模拟

beforeEach(module('gisMobile', function($provide){
    xmlParserMock = {
        readFile: function(){
            var defer = $q.defer();
            defer.resolve(indicatorJsonMock);
            return defer.promise;
        }
    };

    localStorageMock = {
        isStructureCached: false,
        getStructure: function(){
            var defer = $q.defer();
            if(localStorageMock.isStructureCached)
                defer.resolve(indicatorJsonMock);
            else
                defer.reject({name: 'not_found'});
            return defer.promise;
        },
        saveStructure: function(){
            localStorageMock.isStructureCached = true;
        }
    }

    $provide.value('xmlparser', xmlParserMock);
    $provide.value('localStorage', localStorageMock);
}));

最后,测试现在看起来像

it('should list the categories', function(done){
    var promise = Indicator.getCategories()
    .then(function(categories){
        expect(categories[1].name).toBe('Emplois par secteur d\'activité');
        expect(categories[0].name).toBe('Emplois par niveau de compétence');
        done();
    })
    .catch(function(e){
        expect(e).toBe(null);
    });

    $rootScope.$digest();
});

所以关闭这个问题,我的假设是正确的:

  • 我没有正确使用这些优惠
  • 我不得不模拟xmlParser和localStorage,因为它们不是此测试的目标。