tdd – 正确测试附加于$scope的承诺

根据angular.js来源:

$q promises are recognized by the templating engine in angular, which means that in templates you can treat promises attached to a scope as if they were the resulting values.

所以,我有一个控制器,从后端获取类别列表,

function myController($scope, $categoryService) {
...
  $scope.categoriesList = categoryService.search().then(function(response) {
    return response;
  }
...
}

在我的模板中我有一个选择:

<select multiple ng-model="categories" ng-options="category.name for category in categoriesList"></select>

在浏览器中“工作”(选择显示填充列表)

但你怎么测试呢?

我有以下规格:

it('populates the categoriesList from the categoryService', inject(function(categoryService, $q, $controller, $rootScope) {
  var $scope = $rootScope.$new();
  var catList = [{id:1, name:"Animal"},{id:2, name:"Vegetable"}];
  var deferred = $q.defer()
  spyOn(categoryService, 'search').andReturn(deferred.promise);

  $controller(myController, {'$scope': $scope});
  expect(categoryService.search).toHaveBeenCalled(); // PASSES

  deferred.resolve(catList);
  $scope.$digest();

  expect($scope.categoriesList).toEqual(catList); // FAILS, returns the promise instead
}));

如果我像这样重写了我的初始化程序

...then(function(response) {
  $scope.categoriesList = response;
}

我的测试将通过,但后来我没有将范围分配给范围,模板引擎也没有解决对我的承诺.在我看来,第一个实现是框架的意图,但它是不可测试的.第二个实现是可测试的,但不是将数据附加到作用域的预期方法.

最佳答案 当你说

$scope.categoriesList = categoryService.search().then(function(response) {
  return response;
}

$scope.categoriesList未分配响应;相反,它被分配了一个新的promise,它将解析为响应(如测试所示).由于最初的承诺已经解决了响应,你可能只有:

$scope.categoriesList = categoryService.search()

文档的意思是,你可以将$scope.categoriesList分配给这样的promise,并且视图会将表达式categoryList视为它解析的值(在本例中为response) – 它实际上并不接受该值并将其分配给范围.

[更新]

如果您正在测试控制器,而不是类别服务本身,我会完全保留承诺 – 可能是这样的:

it('populates the categoriesList from the categoryService', inject(function(categoryService, $controller, $rootScope) {
  var $scope = $rootScope.$new();
  var catList = [{id:1, name:"Animal"},{id:2, name:"Vegetable"}];
  spyOn(categoryService, 'search').andReturn(catList);

  $controller(myController, {'$scope': $scope});
  expect(categoryService.search).toHaveBeenCalled();

  $scope.$digest();

  expect($scope.categoriesList).toEqual(catList);
}));
点赞