任何人都可以分享单元测试 View 的经验吗?我阅读了很多关于如何使用 View 进行单元测试的教程,但是每样东西都有一些缺点。
我采用了以下方法。它有效,但我想知道是否有更好的方法来做到这一点。也有一些缺点,我稍后会解释。我也在用 Protractor 做 E2E 测试,但它们总是很慢,因此我将它们限制在最低限度。
这是我的 Controller 。它有两个变量绑定(bind)到它的 $scope
在 View 中使用:
// test_ctrl.js
angular.module('app', [])
.controller('TestCtrl', ["$rootScope", "$scope", function ($rootScope, $scope) {
$scope.bar = "TEST";
$scope.jobs = [
{name: "cook"}
];
}]);
View 采用$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
函数,我将设置 Controller 。 createController
函数(从测试本身调用)从 $templateCache
中获取 View , 用它自己的 $scope
创建一个 Controller , 然后它编译模板并触发 $digest
.
模板缓存预填充了 karmas 预处理器 ng-html2js
// karma.conf.js
...
preprocessors: {
'app/views/*.html': 'ng-html2js'
}
...
使用这种方法,我遇到了一个小问题,还有一些疑问:
<强>1。我的对象中的附加 $$hashKey 键来自 ng-repeat
expect($scope.jobs).toEqual([{name: "cook"}]);
在我的测试中抛出一个错误:
Expected [ { name : 'cook', $$hashKey : '009' } ] to equal [ { name : 'cook' } ]
我知道ng-repeat
添加这些键,但这测试起来很愚蠢。我能想到的唯一解决方法是将 Controller 测试和 View 测试分开。但是当我检查 jobs
我的 Controller 内的数组,$$hashKey
不存在。任何想法,为什么会这样?
<强>2。 $范围问题
当我第一次尝试这个时,我只将本地范围定义为 $scope={}
而不是 $scope = $rootScope.$new()
,正如我在其他 Controller 测试中所做的那样。但是只有一个普通对象作为本地范围,我无法编译它($compile(angular.element(html))($scope);
抛出错误)。
我还想通过 $rootScope
是否是个好主意本身作为 Controller 的当前本地范围。这是一个好方法吗?还是有什么缺点,我还没有看到?
<强>3。最佳实践
我很高兴知道其他人是如何在 AngularJS 中进行单元测试的。我认为必须对 View 进行测试,因为对于所有 Angular Directive(指令),它们中都有很多逻辑,我很高兴看到防水 ;)
最佳答案
我认为您正在做的是对 View 进行单元测试的好方法。您问题中的代码对于希望对 View 进行单元测试的人来说是一个很好的方法。
1。 ng-重复 $$hashKey
不要担心数据。相反,测试各种操作的结果,因为这是您一天结束时真正关心的。所以,使用 jasmine-jquery在创建 Controller 后验证 DOM 的状态,并在模拟 click()
s 等之后
2。 $scope = $rootScope.$new() 没问题
$rootScope
是 Scope 的实例,而 $rootScope.$new()
创建 ChildScope的实例强>.使用 ChildScope 的实例进行测试在技术上更正确,因为在生产中, Controller 范围也是 ChildScope 的实例。
顺便说一句,创建隔离范围的单元测试指令也是如此。当您使用 $compile
指令和 ChildScope 实例时,将自动创建一个独立的范围(它是 Scope 的一个实例)。您可以使用 element.isolateScope()
// decalare these variable here so we have access to them inside our tests
var element, $scope, isolateScope;
beforeEach(inject(function($rootScope, $compile) {
var html = '<div my-directive></div>';
// this scope is an instance of ChildScope
$scope = $rootScope.$new();
element = angular.element(html);
$compile(element)($scope);
$scope.$digest();
// this scope is an instance of Scope
isolateScope = element.isolateScope();
}));
3。 +1 测试 View
有人说用 Protractor 测试 View 。当您想测试整个堆栈时,Protractor 非常有用:从前端到后端。然而,Protractor 很慢,单元测试很快。这就是为什么通过模拟依赖于后端的应用程序的任何部分来使用单元测试来测试您的 View 和指令是有意义的。
指令是高度可单元测试的。 Controller 不那么重要。 Controller 可能有很多事件部件,这会使它们更难测试。出于这个原因,我赞成经常创建指令。结果是更易于测试的模块化代码。
关于javascript - 单元测试 View - 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23083645/