4

根据 angular.js 来源:

$q promises 被模板引擎以角度识别,这意味着在模板中,您可以将附加到范围的 promises 视为结果值。

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

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;
}

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

4

2 回答 2

1

当你说

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

$scope.categoriesList未分配response;相反,它被分配了一个的承诺,它解析response(如您的测试所示)。由于最初的承诺已经解决为response,你可以有:

$scope.categoriesList = categoryService.search()

文档的意思是,您可以$scope.categoriesList像这样分配给一个承诺,并且视图会将表达式视为categoriesList它解析为的值(在这种情况下,response) - 它实际上并不采用该值并将其分配给范围.

[更新]

如果您正在测试控制器,而不是 categoryService 本身,我会完全放弃承诺——可能是这样的:

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);
}));
于 2013-01-16T05:58:04.973 回答
1

我遇到了同样的问题,最终在我的测试中这样做:

it("leaves a 'countries' promise that resolves to countries in the scope", function() {
  var value = null;
  scope.countries.then(function(v) {
    value = v;
  });
  scope.$apply();
  expect(value).toEqual([{ Code: "SE", Name: "Sweden" }]);
});

国家而不是类别,但相同的技术应该适用于您的情况。

(我省略了创建范围变量并使用 $httpBackend 设置 GET 期望的 beforeEach,但它们当然是必需的。)

于 2013-05-10T19:00:48.213 回答