【问题标题】:How to mock Angular service method which takes parameter如何模拟带有参数的Angular服务方法
【发布时间】:2015-09-23 16:22:17
【问题描述】:

我正在尝试测试我的 Angular 控制器,并且需要模拟几个服务才能这样做。我将在这个问题中专注于一项服务,因为其余的功能类似。我使用依赖注入来获取playersService 并在我的控制器中使用它:

angular.module('gameApp')
  .controller('PlayerInfoController', PlayerInfoController);

PlayerInfoController.$inject = ['$scope', '$routeParams', 'playersService'];

function PlayerInfoController($scope, $routeParams, playersService) {
  var vm = this;
  var playerId = $routeParams.playerId;

  playersService.getDetails({
    playerId: playerId
  }).$promise.then(function(details) {
    vm.details = details;
  });
}

相关服务如下所示:

angular.module('gameApp')
  .factory('playersService', ['$resource',
    function($resource) {
      var base = '/api/players/:playererId/';
      return $resource(base, {}, {
        getDetails: {method: 'GET', url: base + 'details'}
      });
    }]);

以下是我当前的单元测试设置,它失败并出现以下错误:TypeError: 'undefined' is not an object (evaluating 'playersService.getDetails({playerId: playerId}).$promise.then')

describe('PlayerInfoController', function() {
  var scope;
  var routeParams;
  var playersService;

  beforeEach(function() {
    var mockPlayersService = {};
    module('gameApp', function($provide) {
      $provide.value('playersService', mockPlayersService);
    });
    inject(function($q) {
      mockPlayersService.details = {
        'firstName': 'John',
        'lastName': 'Doe',
        'country': 'US'
      };

      mockPlayersService.getDetails = function(playerId) {
        var defer = $q.defer();
        defer.resolve(this.details);
        return defer.promise;
      };
    });
  });

  beforeEach(inject(function($controller, $rootScope, _$routeParams_, _playersService_) {
    scope = $rootScope.$new();
    routeParams = _$routeParams_;
    playersService = _playersService_;

    $controller('PlayerInfoController', {$scope: scope, $routeParams: routeParams, playersService: playersService});

    scope.$digest();
  }));

  it('should say 2 === 2', function() {
    expect(2).toEqual(2);
  });
});

【问题讨论】:

  • 这可能不是错误,但“playersService.getDetails({ playerId: playerId }).$promise.then” 行中不需要“$rpomise”:getDetails 应该已经返回了一个 promise

标签: javascript angularjs unit-testing jasmine promise


【解决方案1】:

playersService.getDetails 通常会返回一个具有 $promise 属性的相对空的对象,一旦调用完成,这个对象就会被填充结果。

你的 mockPlayersService.getDetails 需要返回一个类似的对象,所以应该这样做:

mockPlayersService.getDetails = function(playerId) {
    var defer = $q.defer();
    defer.resolve(this.details);
    return angular.extend({$promise: defer.promise}, this.details);
  };

请注意,根据角度文档,您通常会像这样使用您的服务(第二个参数可以是调用成功而不是使用 $promise 的函数)。

playersService.getDetails({
  playerId: playerId
}, function(details) {
  vm.details = details;
});

这还需要您修改模拟服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    相关资源
    最近更新 更多