【发布时间】:2014-04-15 12:23:36
【问题描述】:
任何人都可以分享单元测试视图的经验吗?我阅读了很多关于如何使用视图进行单元测试的教程,但一切都有一些缺点。
我采用了以下方法。它有效,但我想知道是否有更好的方法来做到这一点。还有一些缺点,我稍后会解释。我也在用量角器进行 E2E 测试,但它们总是很慢,因此我将它们限制在最低限度。
这是我的控制器。它有两个绑定到其$scope 的变量,这些变量在视图中使用:
// test_ctrl.js
angular.module('app', [])
.controller('TestCtrl', ["$rootScope", "$scope", function ($rootScope, $scope) {
$scope.bar = "TEST";
$scope.jobs = [
{name: "cook"}
];
}]);
视图将$scope.bar 放入<span> 并将$scope.jobs 数组放入ng-repeat 指令:
<!-- test.html the view for this controller -->
<span>
Bar is {{bar || "NOT SET"}}
</span>
<ul>
<li ng-repeat="job in jobs">{{job.name}}</li>
</ul>
这是测试:
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。
模板缓存预填充了业力预处理器 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 = $rootScope.$new(),就像我在其他控制器测试中所做的那样。但是只有一个普通对象作为本地范围,我无法编译它($compile(angular.element(html))($scope); 抛出错误)。
我还认为将$rootScope 本身作为控制器的当前本地范围传递是否是个好主意。这是一个好方法吗?还是有什么缺点,我还没看到?
3.最佳做法
我很高兴知道其他人是如何在 AngularJS 中进行单元测试的。我认为必须对视图进行测试,因为在所有角度指令中,其中包含很多逻辑,我很高兴看到防水 ;)
【问题讨论】:
-
值得注意的是,在 ng-repeat 指令中使用 track by 表达式可能会帮助您摆脱哈希键(并加快查找速度)。见codelord.net/2014/04/15/…
-
这与单元测试无关,但是在查看了示例控制器之后,我想在此处留下这条评论,以供路过的程序员博学:不污染
$scope是一个好习惯使用控制器的局部变量。最好使用this.bar = "TEST",并在视图中使用ng-controller="TestCtrl as ctrl"和ctrl.bar引用它。
标签: javascript angularjs unit-testing testing