单元测试视图 - 最佳实践

8 浏览
0 Comments

单元测试视图 - 最佳实践

有人能分享一下关于单元测试视图的经验吗?我看了很多关于如何使用视图进行单元测试的教程,但是每种方法都有一些缺点。

我找到了以下方法,它能正常工作,但我想知道是否有更好的方法。同时,也存在一些缺点,我稍后会解释。我也正在使用protractor进行E2E测试,但它们总是很慢,因此我将它们限制在最小范围内。

这是我的控制器。它有两个变量绑定到它的$scope上,这些变量在视图中使用:

// test_ctrl.js
angular.module('app', [])
  .controller('TestCtrl', ["$rootScope", "$scope", function ($rootScope, $scope) {
    $scope.bar = "TEST";
    $scope.jobs = [
      {name: "cook"}
    ];
  }]);

视图将$scope.bar放入一个``中,并将$scope.jobs数组放入一个`ng-repeat`指令中:



  Bar is {{bar || "NOT SET"}}

  • {{job.name}}

以下是测试代码:

describe('Controller: TestCtrl', function () {
  beforeEach(module('templates'));
  beforeEach(module('app'));
  var TestCtrl, $rootScope, $compile, createController, view, $scope;
  beforeEach(inject(function($controller, $templateCache, _$rootScope_, _$compile_, _$httpBackend_) {
    $rootScope = _$rootScope_;
    $scope = $rootScope.$new();
    $compile = _$compile_;
    createController = function() {
      var html = $templateCache.get('views/test.html');
      TestCtrl = $controller('TestCtrl', { $scope: $scope, $rootScope: $rootScope });
      view = $compile(angular.element(html))($scope);
      $scope.$digest();
    };
  }));
  it('should test the view', function() {
    createController();
    expect(view.find("li").length).toEqual(1)
    console.log($scope.jobs)
  });
});

在`beforeEach`函数中,我设置了控制器。`createController`函数(从测试代码中调用)从`$templateCache`中获取一个视图,使用自己的`$scope`创建一个控制器,然后编译模板并触发`$digest`。

模板缓存使用karma的预处理器ng-html2js填充:

// karma.conf.js
...
preprocessors: {
  'app/views/*.html': 'ng-html2js'
}
...

使用这种方法,我遇到了一些问题,并有一些疑问:

1. ng-repeat在对象中添加了额外的$$hashKey键

我的测试中的`expect($scope.jobs).toEqual([{name: "cook"}]);`抛出了错误:

Expected [ { name : 'cook', $$hashKey : '009' } ] to equal [ { name : 'cook' } ]

我知道`ng-repeat`会添加这些键,但测试这个很傻。我能想到的唯一解决办法是分离控制器测试和视图测试。但是当我在控制器中检查`jobs`数组时,`$$hashKey`不存在。有什么想法,为什么会发生这种情况吗?

2. $scope问题

当我第一次尝试时,我只定义了一个本地作用域`$scope={}`,而不是像在其他控制器测试中那样使用`$scope = $rootScope.$new()`。但是,只有一个普通对象作为本地作用域时,我无法编译它(`$compile(angular.element(html))($scope);`会抛出错误)。

我也在考虑是否将`$rootScope`本身作为当前本地作用域传递给控制器是一个好方法。这是一个好的方法吗?或者还有我没有看到的任何缺点吗?

3. 最佳实践

我很想知道其他人是如何在AngularJS中进行单元测试的。我认为视图必须进行测试,因为在所有的angular指令中,它们中包含了很多逻辑,我很乐意看到它们得到完善;)

0