javascript - 如何模拟带有参数的 Angular 服务方法

标签 javascript angularjs unit-testing jasmine promise

我正在尝试测试我的 Angular Controller ,并且需要模拟多个服务才能执行此操作。我将重点关注这个问题中的一项服务,因为其余服务的功能类似。我使用依赖注入(inject)来获取 playersService 并在我的 Controller 中像这样使用它:

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 通常会返回一个具有 $promise 属性的相对空的对象,一旦调用完成,该对象就会填充结果。

您的mockPlayersService.getDetails需要返回一个类似的对象,因此应该这样做:

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

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

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

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

关于javascript - 如何模拟带有参数的 Angular 服务方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31247241/

相关文章:

angularjs - Firebase - limitToLast(5),然后加载以前的数据

php - 如何表明 PHPUnit 测试预计会失败?

javascript - 及时绘制 HTML5/Javascript Canvas 路径

javascript - 如何制作类似 "webmail"的文件附加/上传

javascript - 数据类型 Jasmine

unit-testing - Angular 2——模拟——没有 HTTP 提供者

java - 如何测试使用 Selenium 的 Java 代码?

javascript - 谷歌电子表格: Insert Rows and copy down hidden content

javascript - 如何在 JavaScript 中使用特定变量来定位对象

javascript - 自动刷新 .filter() 范围