如何在Jasmine测试中模拟Angular $ q服务?

Jas*_*son 4 javascript unit-testing jasmine angularjs angular-promise

我正在尝试测试一个Angular服务,它有2个依赖项,一个在$ q上,另一个在'myService'上,它也依赖于$ q.

(function() {
    'use strict';

    angular.module('myModule').factory('myService', [
        '$q',
        'apiService',
        function($q, apiService) {

            var data = null;

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

                if (data === null) {

                    apiService.get('url').then(function(result) {
                        data = result;
                        deferred.resolve(data);
                    }, function() {
                        deferred.reject();
                    });
                } else {
                    deferred.resolve(data);
                }

                return deferred.promise;
            }

            return {
                getData: getData
            };
        }
    ]);
})();
Run Code Online (Sandbox Code Playgroud)

我开始编写一个Jasmine测试,如下所示,但是有问题嘲笑$ q.我想将$ q的真实版本而不是模拟版本注入'myService'和'apiService',但我不知道如何实现这一目标.

'use strict';

describe('My service', function() {
    var qSpy, apiServiceSpy;

    beforeEach(module('myModule'));

    beforeEach(function() {
        qSpy = jasmine.createSpyObj('qSpy', ['defer']);

        apiServiceSpy = jasmine.createSpyObj('apiServiceSpy', ['get']);
        apiServiceSpy.get.and.callFake(function() {
            var deferred = $q.defer();
            deferred.resolve('Remote call result');
            return deferred.promise;
        });

        module(function($provide) {
            $provide.value('$q', qSpy);
            $provide.value('apiService', apiServiceSpy);
        });
    });

    it('should get data.', inject(function(myService) {
        // Arrange

        // Act
        var data = myService.getData();

        // Assert
        expect(data).not.toBeNull();
    }));
});
Run Code Online (Sandbox Code Playgroud)

编辑 这是基于以下响应的更新测试.我想我的问题是我认为我必须提供$ q.

'use strict';

describe('My service', function() {
    var service, apiServiceSpy;

    beforeEach(module('myModule'));

    beforeEach(function() {
        apiServiceSpy = jasmine.createSpyObj('apiServiceSpy', ['get']);

        module(function($provide) {
            $provide.value('apiService', apiServiceSpy);
        });
    });

    beforeEach(inject(function($q, myService) {
        service = myService;

        apiServiceSpy.get.and.callFake(function() {
            var deferred = $q.defer();
            deferred.resolve('Remote call result');
            return deferred.promise;
        });
    }));

    it('should get data.', function() {
        // Arrange

        // Act
        var data = service.getData();

        // Assert
        expect(data).not.toBeNull();
    }));
}); 
Run Code Online (Sandbox Code Playgroud)

han*_*aad 11

你可以使用真正的$ q.重要的是要注意,您应该致电$scope.$apply()解决承诺.

var service;
var $scope;
beforeEach(function() {

    angular.mock.module('app', function ($provide) {
        $provide.value('apiService', apiServiceSpy);
    });

    angular.mock.inject(function (_myService_, _$rootScope_) {
        service = _myService_;
        $scope = _$rootScope_;
    });
});

it('works like a charm', function() {
    var data;
    service.getData().then(function(d) {
        data = d;
    });
    $scope.$apply();  // resolve promise
    expect(data).toBeAwesomeData();
});
Run Code Online (Sandbox Code Playgroud)