使用angular / karma / jasmine模拟异步服务功能

时间:2014-08-12 21:13:57

标签: javascript angularjs asynchronous mocking karma-jasmine

此代码中的测试未成功。我似乎无法成功测试异步函数的返回。

describe('mocking services', function () {

    var someService, deferred;

    beforeEach(function () {

        module(function($provide){
            $provide.factory('someService', function($q){
                return{
                    trySynch: function(){
                        return 33;
                    },
                    tryAsynch: function(){
                        deferred = $q.defer();
                        return deferred.promise;
                    }
                };
            });
        });

        inject(function (_someService_) {
            someService = _someService_;
        });
    });

    it('should be able to test values from both functions', function () {
        expect(someService.trySynch()).toEqual(33);

        var retVal;
        someService.tryAsynch().then(function(r){
            retVal = r;
        });
        deferred.resolve(44);
        expect(retVal).toEqual(44);
    });

});

当我运行它时,我收到以下错误:

Chrome 36.0.1985 (Mac OS X 10.9.4) mocking services should be able to test values from both functions FAILED
        Expected undefined to equal 44.
        Error: Expected undefined to equal 44.
            at null.<anonymous> (/Users/selah/WebstormProjects/macrosim-angular/test/spec/services/usersAndRoles-service-test.js:34:24)

如何让这个测试通过?

3 个答案:

答案 0 :(得分:2)

使用$ q模拟异步调用时,由于$ q的实现方式,您需要使用$rootScope.$apply()

具体来说,.then方法不会被同步调用,它被设计为始终是异步的,无论它是如何调用的 - 同步或异步。

为实现这一目标,$ q与$ rootScope集成。因此,在单元测试中,您需要通知$ rootScope更改了某些内容(即 - 触发摘要周期)。为此,请致电$rootScope.$apply()

请参阅here (specifically the "Differences between Kris Kowal's Q and $q section")

工作代码如下所示:

describe('mocking services', function () {

    var someService, deferred, rootScope;

    beforeEach(function () {

        module(function($provide){
            $provide.factory('someService', function($q){
                return{
                    trySynch: function(){
                        return 33;
                    },
                    tryAsynch: function(){
                        deferred = $q.defer();
                        return deferred.promise;
                    }
                };
            });
        });

        inject(function ($injector) {
            someService = $injector.get('someService');
            rootScope = $injector.get('$rootScope');
        });
    });

    it('should be able to test values from both functions', function () {
        expect(someService.trySynch()).toEqual(33);

        var retVal;
        someService.tryAsynch().then(function(r){
            retVal = r;
        });
        deferred.resolve(44);
        rootScope.$apply();
        expect(retVal).toEqual(44);
    });

});

答案 1 :(得分:0)

$q延迟仍然是异步解析。

快速测试,尽管是旧版Angular:http://plnkr.co/edit/yg2COXG0TWBYniXOwJYb

此测试应该有效:

it('should be able to test values from both functions', function (done) {

    expect(someService.trySynch()).toEqual(33);

    someService.tryAsynch().then(function(r){
        expect(r).toEqual(44);
        done();
    });

    deferred.resolve(44);
});

答案 2 :(得分:0)

如果我在测试我的异步函数的expect子句之前运行rootScope.$apply(),那么测试成功。此外,如果我提供的值不正确,它会失败,正如我所期望的那样。

所以我的测试功能正常,但我不明白为什么rootScope。$ apply()在这里很重要,所以如果有人想复制我的代码并提供解释,我很乐意将你的答案标记为正确解答!

我的工作测试代码如下所示:

describe('mocking services', function () {

    var someService, deferred, rootScope;

    beforeEach(function () {

        module(function($provide){
            $provide.factory('someService', function($q){
                return{
                    trySynch: function(){
                        return 33;
                    },
                    tryAsynch: function(){
                        deferred = $q.defer();
                        return deferred.promise;
                    }
                };
            });
        });

        inject(function ($injector) {
            someService = $injector.get('someService');
            rootScope = $injector.get('$rootScope');
        });
    });

    it('should be able to test values from both functions', function () {
        expect(someService.trySynch()).toEqual(33);

        var retVal;
        someService.tryAsynch().then(function(r){
            retVal = r;
        });
        deferred.resolve(44);
        rootScope.$apply();
        expect(retVal).toEqual(44);
    });

});