如何在AngularJS单元测试中模拟promise的结果? [英] How do I mock the result of a promise in an AngularJS unit test?

查看:68
本文介绍了如何在AngularJS单元测试中模拟promise的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 CompanyService 是:

angular.module('mean').service('CompanyService', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
  var company = this;
  var initializedDeferred = $q.defer();

  company.company_data = {}
  company.initialized = initializedDeferred.promise;

  company.getCompany = function() {
    return company.company_data;
  }

  company.get = function (company_id) {
    return $http({
      url: '/api/v1/company/' + company_id,
      method: 'GET',
      headers: {
        api_key: $rootScope.api_key
      }
    }).success(function(response) {
      if(response.status === 'ok') {
        company.company_data = response.company;
        initializedDeferred.resolve();
      } else {
        alert('TBD: Need fail case');
      }
    });
  };
}]);

我的控制器是:

angular.module('mean').controller('LocationController', ['$scope', '$location', '$rootScope', 'LocationService', 'UserService', 'CompanyService', '$modal', '$routeParams', function ($scope, $location, $rootScope, LocationService, UserService, CompanyService, $modal, $routeParams) {
  $rootScope.menuItem = 'locations';
  $scope.contentTemplate = '/views/location/index.html';
  $scope.locations = [];
  $scope.current_location = null;
  $scope.newLocation = {};
  $scope.location_parent_id = $routeParams.location_parent_id;

  $scope.index = function() {
    CompanyService.initialized.then(function() {
      $scope.test = 'a';
      var company_id = CompanyService.getCompany()._id;
      LocationService.list(company_id, $routeParams.location_parent_id).then(function(response) {
        if(response.data.status === 'ok') {
          $scope.locations = response.data.locations;
          $scope.current_location = response.data.location || null;
        }
      });
    });
  }

  $scope.addLocationModal = function() {
    $scope.location_types = ['warehouse', 'section', 'row', 'shelf', 'bin'];
    $modal({
      scope: $scope,
      template: '/views/location/addLocationModal.html',
      show: true,
      animation: 'am-fade-and-scale'
    });
  }

  $scope.createLocation = function() {
    $scope.newLocation.company_id = CompanyService.getCompany()._id;
    LocationService.create($scope.newLocation).then(function(response) {
      if(response.data.status === 'ok') {
        $scope.$hide();
      } else {
        alert('TBD');
      }
    });
  }

}]);

我的测试是:

(function() {
  describe('LocationController', function() {
    var $scope, $location, $rootScope, $modal, deferred, CompanyService, createController;

    beforeEach(module('mean'));

    beforeEach(inject(function($injector) {
      $location = $injector.get('$location');
      $rootScope = $injector.get('$rootScope');
      $modal = $injector.get('$modal');
      $scope = $rootScope.$new();

      var $controller = $injector.get('$controller');

      var $q = $injector.get('$q');

      var params = {
        '$scope': $scope,
        CompanyService: jasmine.createSpyObj('CompanyService', ['initialized'])
      }

      params.CompanyService.initialized.andCallFake(function () {
        deferred = $q.defer();
        return deferred.promise;
      });


      createController = function() {
        return $controller('LocationController', params);
      };
    }));

    it('should instantiate initial variables at the top level', function() {
      var controller = createController();

      $location.path('/company/locations');
      expect($location.path()).toBe('/company/locations');
      expect($rootScope.menuItem).toBe('locations');
      expect($scope.contentTemplate).toBe('/views/location/index.html');
      expect($scope.locations.length).toEqual(0);
      expect($scope.current_location).toBeNull();
      expect($scope.newLocation).toBeDefined();
      expect($scope.location_parent_id).not.toBeDefined();
    });

    it('should list all locations for this company', function() {
      var controller = createController();
      deferred.resolve();
      $scope.index();

      expect($scope.test).toBe('a');
    });
  });
})();

但是,解决无效。我收到此错误:
TypeError:'undefined'不是对象(评估'deferred.resolve')

But, the resolve isn't working. I get this error: TypeError: 'undefined' is not an object (evaluating 'deferred.resolve')

任何帮助?

推荐答案

在测试中,使用假的 CompanyService创建延迟对象.initialized 功能。但是,只有在调用 $ scope.index(); 时才会调用此函数,该函数在 deferred.resolve(); 行。以下应该有效:

In your tests you create your deferred object using the fake CompanyService.initialized function. However this function is only called when you call $scope.index();, which is executed after your deferred.resolve(); line. The following should work:

it('should list all locations for this company', function() {
  var controller = createController();
  $scope.index();   // Should in turn call the fake CompanyService.initialized function that creates deferred
  deferred.resolve();
  $scope.$apply();  // Fire $digest cycle to dispatch promises.

  expect($scope.test).toBe('a');
});

更新

Jasmine不支持监视非函数的属性。所以你的间谍设置​​无效,因为 CompanyService.initialized 是一个对象而不是一个函数,所以你的 andCallFake 不会工作。解决方法是在 CompanyService 中引入一个getter函数,例如:

Jasmine doesn't support spying on properties that are not functions. So your spy setup is invalid as CompanyService.initialized is an object and not a function, so your andCallFake wont work. A workaround is to introduce a getter function inside your CompanyServicee.g:

company.isInitialized(){ return company.initialized; }

然后在你的控制器中使用这个getter函数:

And then inside your controller use this getter function instead:

$scope.index = function() {
  CompanyService.isInitialized().then(function() {
    $scope.test = 'a';
    // Removed for brevity
  });
}

最后更新测试代码初始化:

And finally update your test code initialization:

var params = {
  '$scope': $scope,
  CompanyService: jasmine.createSpyObj('CompanyService', ['isInitialized'])
}
params.CompanyService.isInitialized.andCallFake(function () {
  deferred = $q.defer();
  return deferred.promise;
});

这篇关于如何在AngularJS单元测试中模拟promise的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆