簡體   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