繁体   English   中英

Jasmine单元测试不等待承诺解决

[英]Jasmine unit tests not waiting for promise resolution

我有一个像这样的异步依赖的角度服务

(function() {
    angular
        .module('app')
        .factory('myService', ['$q', 'asyncService',

    function($q, asyncService) {

        var myData = null;

        return {
            initialize: initialize,
        };

        function initialize(loanId){
            return asyncService.getData(id)
                .then(function(data){
                    console.log("got the data!");
                    myData = data;
            });
        }
    }]);
})();

我想单元测试initialize函数,我正在尝试像这样的茉莉:

describe("Rate Structure Lookup Service", function() {

    var $q;
    var $rootScope;
    var getDataDeferred;
    var mockAsyncService;
    var service;

    beforeEach(function(){
        module('app');

        module(function ($provide) {
            $provide.value('asyncService', mockAsyncService);
        });

        inject(function(_$q_, _$rootScope_, myService) {
            $q = _$q_;
            $rootScope = _$rootScope_;
            service = myService;
        });

        getDataDeferred = $q.defer();

        mockAsyncService = {
            getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
        };
    });

    describe("Lookup Data", function(){
        var data;

        beforeEach(function(){
            testData = [{
                recordId: 2,
                effectiveDate: moment("1/1/2015", "l")
            },{
                recordId: 1,
                effectiveDate: moment("1/1/2014", "l")
            }];
        });

        it("should get data", function(){
            getDataDeferred.resolve(testData);

            service.initialize(1234).then(function(){
                console.log("I've been resolved!");
                expect(mockAsyncService.getData).toHaveBeenCalledWith(1234);
            });

            $rootScope.$apply();
        });
    });
});

没有任何控制台消息出现,测试似乎只是在没有承诺得到解决的情况下继续进行。 我虽然$rootScope.$apply()会这样做,但似乎没有。

UPDATE

@estus是对的$rootScope.$appy()足以触发所有承诺的解决。 似乎问题出在我对asyncService的模拟中。 我把它改成了

mockAsyncService = {
    getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
};

mockAsyncService = {
    getData: jasmine.createSpy('getData').and.callFake(
        function(id){
            return $q.when(testData);
    })
};

我将testData设置为我需要的测试,而不是调用getDataDeferred.resolve(testData) 这种变化之前,mockAsyncService被注射但是对于承诺getDataDeferred从来没有得到解决。

我不知道这是否是在beforeEach中注入的beforeEach或什么。 更奇怪的是,这必须是一个callFake 使用.and.returnValue($q.when(testData))仍会阻止承诺解析。

角度承诺在测试期间是同步的, $rootScope.$apply()足以使它们在规范结束时结算。

除非asyncService.getData返回一个真正的promise而不是$q promise(在这种情况下它不会),asynchronicity在Jasmine中不是问题。

Jasmine promise matchers库非常适合测试Angular的承诺。 除了明显缺乏冗长之外,它还在这种情况下提供了有价值的反馈。 虽然这个

rejectedPromise.then((result) => {
  expect(result).toBe(true);
});

规范将在不应该的时候通过,这个

expect(pendingPromise).toBeResolved();
expect(rejectedPromise).toBeResolvedWith(true);

将失败的有意义的消息。

测试代码的实际问题在beforeEach是优先的。 角度自举过程不同步。

getDataDeferred = $q.defer()应该放入inject块,否则它将在模块被引导并且注入$q之前执行。 同样的担忧mockAsyncService使用getDataDeferred.promise

在最好的情况下,代码会抛出错误,因为在undefined调用了defer方法。 在最坏的情况下(这就是为什么这样的规范属性this.$q比本地套件变量更可取的原因) $q属于前一个规范的一个注入器,因此$rootScope.$apply()在这里没有效果。

您需要将可选的done参数传递给it块中的回调函数。 否则jasmine无法知道你正在测试异步函数 - 异步函数会立即返回。

这是重构:

it("should get data", function(done){

    service.initialize(1234).then(function(){
        console.log("I've been resolved!");
        expect(mockAsyncService.getData).toHaveBeenCalledWith(1234);
        done();
    });  
});

这里有一些(片状,背面的啤酒垫)指针。 不幸的是,我无法知道它们是否是实际错误,或者它们是否是“拼写错误”,因为您“简化”了代码。

首先,没有理由不将asyncService作为服务和内联提供。 试试这个:

$provide.service('asyncService', function() {
    // asyncService implementation
});

另外,我不相信这种依赖注入会起作用。

inject(function(_$q_, _$rootScope_, myService) {
    $q = _$q_;
    $rootScope = _$rootScope_;
    service = myService;
});

因为DI容器不知道myServiceProvider。 你可以试试这个:

inject(function(_$q_, _$rootScope_, _asyncService_) {
    $q = _$q_;
    $rootScope = _$rootScope_;
    service = _asyncService_;
});

哪个会起作用,因为您之前使用'asyncService'作为参数调用$ provide。

另外,你没有正确使用$ promise api。 你没有在单元测试中向.then()返回resolve()'s promise。 尝试使用asyncService的替代实现,类似于:

$provide.service('asyncService', function() {
    this.getData = function() {
        return $q(function(resolve, reject) {
         resolve('Promise resolved');
        });
    }
});

查看$ q文档

你可以在你的单元测试中监视这个。 没有理由在beforeEach()函数中调用间谍。

jasmine.spyOn(service, 'getData').and.callThrough();

你的期望()看起来不错。

如果有任何这些对你有帮助,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM