有人能分享一下关于单元测试视图的经验吗?我读了很多有关如何对视图进行单元测试的教程,但每种方法都有一些缺点。
我采用了以下方法。它有效,但我想知道是否有更好的方法来做这件事。同时也存在一些缺点,稍后我会解释。我还使用protractor进行端到端测试,但它们总是很慢,因此我将其限制在最小范围内。
这是我的控制器。它绑定了两个变量到它的$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
。模板缓存使用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 指令会涉及许多逻辑,我希望看到这些逻辑被验证。
$scope
与控制器的本地变量。最好使用this.bar = "TEST"
,并在视图中使用ng-controller="TestCtrl as ctrl"
和ctrl.bar
进行引用。 - jrharshath