【问题标题】:Service has a mocked service dependency which returns promise, struggling with testing服务有一个模拟的服务依赖,它返回承诺,在测试中苦苦挣扎
【发布时间】:2015-08-18 13:56:59
【问题描述】:

我有三项服务。 RequestAuthorizationService 调用 OAuthAuthorizationDataService 以获取基于令牌的授权的凭据,凭据将由 sessionStorageManagerService 存储在会话存储中,因此它们被传递.

测试主体是sessionStorageManagerService.set()方法获取数据时的调用。我想确定它是否被调用。

当我检查 then 块中调用的方法是否时,我不知道自己做错了什么。测试总是说该方法没有被调用。 我在这里浏览了很多文章,但我不知道该怎么做。

提前感谢您的帮助!

代码如下:

请求授权服务

(function () {
    'use strict';

    var serviceId = 'requestAuthorizationService';

    angular
        .module('dilib')
        .service(serviceId, requestAuthorizationService);

    requestAuthorizationService.$inject = ['$q', 'Restangular', 'cryptoService', 'OAuthAuthenticationDataService', 'sessionStorageManagerService'];

    function requestAuthorizationService($q, Restangular, cryptoService, OAuthAuthenticationDataService, sessionStorageManagerService) {

        //API
        var service = {

            requestAuthorization: requestAuthorization,
        }

        return service;

        /////////////////////////////////////////////////////////////////////

        function requestAuthorization(user) {

            var defer = $q.defer();

            var userLocal = undefined;

            if (typeof user === "undefined") {

                userLocal = {
                    username: 'visitor',
                    password: cryptoService.getMD5('qwe123')
                };
            } else {

                userLocal = user;

            }

            OAuthAuthenticationDataService.authenticate(userLocal).then(function (result) {

                //To be tested
                sessionStorageManagerService.set('authorizationData',
                {
                    token: result.access_token,
                    username: user.username
                });

                defer.resolve(userdata.username);

            }, function (msg) {

                defer.reject(msg);

            });

            return defer.promise;
        }

    }
})();

OAuthAuthenticationDataService

(function () {
    'use strict';

    var serviceId = 'OAuthAuthenticationDataService';

    angular
        .module('dilib')
        .service(serviceId, OAuthAuthenticationDataService);

    OAuthAuthenticationDataService.$inject = ['Restangular'];

    function OAuthAuthenticationDataService(Restangular) {

        var OAuthHttpHeader = {
            "Content-Type": 'application/x-www-form-urlencoded'
        };

        var oAuthEndpointResource = Restangular.all('/token');

        var service = {

            authenticate : authenticate

        }

        return service;


        function authenticate(user) {

            return oAuthEndpointResource.post('grant_type=password&username=' + user.username + '&password=' + user.password, {}, OAuthHttpHeader);

        }
    }
})();

sessionStorageManagerService

(function () {
    'use strict';

    var serviceId = 'sessionStorageManagerService';

    angular
        .module('dilib')
        .service(serviceId, sessionStorageManagerService);

    sessionStorageManagerService.$inject = ['localStorageService'];

    function sessionStorageManagerService(localStorageService) {

        var service = {

            get: get,
            set: set

        };

        return service;

        function set(key, val) {

            localStorageService.set(key, val);

        }

        function get(key) {

            return localStorageService.get(key);

        }

    }
})();

测试

describe('requestAuthorizationService', function () {

    var RestangularProvider,
        localStorageServiceProvider,
        cryptoServiceMockSvc,
        OAuthAuthenticationDataServiceMockSvc,
        sessionStorageManagerServiceMockSvc,
        requestAuthorizationService,
        $q,
        $rootScope;

    beforeEach(function () {

        angular.module('ngAnimate', []);
        angular.module('ngRoute', []);
        angular.module('dilib.layout', []);
        //angular.module('LocalStorageModule', []);
        angular.module('http-auth-interceptor', []);
        //angular.module('restangular', []);

    });

    beforeEach(function () {

        module('dilib', function (_RestangularProvider_, _localStorageServiceProvider_) {

            RestangularProvider = _RestangularProvider_;
            localStorageServiceProvider = _localStorageServiceProvider_;

        });

    });

    //beforeEach(inject());

    beforeEach(function () {

        module(function ($provide) {

            $provide.service('cryptoService', function () {
                this.getMD5 = jasmine.createSpy('getMD5').and.callFake(function (param) {

                    var returnVal;

                    if (param == 'qwe123') {

                        returnVal = '200820e3227815ed1756a6b531e7e0d2';
                    }

                    if (param == 'qwe321') {

                        returnVal = 'blabla';
                    }

                    return returnVal;
                });
            });

            $provide.service('OAuthAuthenticationDataService', function () {
                this.authenticate = jasmine.createSpy('authenticate').and.callFake(function (userObject) {

                    var defer = $q.defer();
                    defer.resolve({ access_token: '1234' });
                    return defer.promise;

                });
            });

            $provide.service('sessionStorageManagerService', function () {

                this.get = jasmine.createSpy('get').and.callFake(function(param) {
                    return param;
                });
                this.set = jasmine.createSpy('set').and.callFake(function(param) {
                    return param;
                });

            });

        });

    });

    beforeEach(inject(function (cryptoService,
                                OAuthAuthenticationDataService,
                                sessionStorageManagerService,
                                _requestAuthorizationService_,
                                _$q_,
                                _$rootScope_) {

        cryptoServiceMockSvc = cryptoService;
        OAuthAuthenticationDataServiceMockSvc = OAuthAuthenticationDataService;
        sessionStorageManagerServiceMockSvc = sessionStorageManagerService;
        requestAuthorizationService = _requestAuthorizationService_;
        $q = _$q_;
        $rootScope = _$rootScope_;

    }));

    describe('requestAuthorization method', function () {

        describe('OAuth authentication result will be passed through sessionStorageManager', function () {

            it('default value result will be passed through', function () {

                //try 1
                // OAuthAuthenticationDataServiceMockSvc.authenticate().then(function(result) {

                    // console.log('result', result);

                    // expect(sessionStorageManagerServiceMockSvc.set).toHaveBeenCalled();

                // });

                // $rootScope.$digest();

                //try 2
                // OAuthAuthenticationDataServiceMockSvc.authenticate();

                // expect(sessionStorageManagerServiceMockSvc.set).toHaveBeenCalled();

                // $rootScope.$digest();

            });

        });

    });

});

【问题讨论】:

    标签: javascript angularjs unit-testing jasmine promise


    【解决方案1】:

    Authenticate 有假实现,它不调用 sessionStorageManagerService。

    我在您的代码中没有看到任何 sessionStorageManagerService.set 调用。

    【讨论】:

      【解决方案2】:

      我认为这应该会有所帮助

      var $scope;
      var $q;
      var deferred;
      var sessionStorageManagerService;
      var requestAuthorizationService;
      var OAuthAuthenticationDataService;
      
      /* Mock another required modules */
      
      beforeEach(function() {
          angular.mock.module(function($provide) {
              sessionStorageManagerService = jasmine.createSpyObj('sessionStorageManagerService', ['set', 'get']);
      
              $provide.value('sessionStorageManagerService', sessionStorageManagerService);
          });
      });
      
      beforeEach(function() {
          angular.mock.module(function($provide) {
              OAuthAuthenticationDataService = jasmine.createSpyObj('OAuthAuthenticationDataService', ['authenticate']);
      
              $provide.value('OAuthAuthenticationDataService', OAuthAuthenticationDataService);
          });
      });
      
      beforeEach(function() {
          angular.mock.module(function($provide) {
              requestAuthorizationService = jasmine.createSpyObj('requestAuthorizationService', ['requestAuthorization']);
      
              $provide.value('requestAuthorizationService', requestAuthorizationService);
          });
      });
      
      beforeEach(inject(function(_$rootScope_, _$q_, _sessionStorageManagerService_, _requestAuthorizationService_, _OAuthAuthenticationDataService_) {
          $scope = _$rootScope_.$new();
          $q = _$q_;
          sessionStorageManagerService = _sessionStorageManagerService_;
          requestAuthorizationService = _requestAuthorizationService_;
          OAuthAuthenticationDataService = _OAuthAuthenticationDataService_;
          deferred = $q.defer();
      
      requestAuthorization.requestAuthorization.and.returnValue(deferred.promise);
      OAuthAuthenticationDataService.authenticate.and,returnValue(deferred.promise);
      
          $scope.$digest();
      }));
      
      it('', function() {
          var user = {};
      
          requestAuthorizationService.requestAuthorization(user);
          deferred.resolve({});
          $scope.$digest();
      
          expect(OAuthAuthenticationDataService.authenticate).toHaveBeenCalledWith(...);
          expect(sessionStorageManagerService.set).toHaveBeenCalledWith(...);
      });
      
      it('', function() {
          var user = {};
      
          requestAuthorizationService.requestAuthorization(user);
          deferred.reject({});
          $scope.$digest();
      
          expect(...);
      });
      

      【讨论】:

      • 感谢您的回答。我是否理解正确,上面的示例您注入原始服务并将 spyObjects 放在特定方法上?
      • 是的。我将所有服务都创建为 jasmine 间谍对象。并且返回 promise 的函数必须返回 deferred.promise。为了测试函数的成功或错误结果,请使用延迟解析/拒绝和 $scope.$digest 或 $scope.$apply 来解决所有承诺。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多