单元测试视图-最佳实践 [英] Unit test views - best practice

查看:51
本文介绍了单元测试视图-最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以分享单元测试视图的经验吗?我阅读了很多有关如何使用视图进行单元测试的教程,但是所有内容都有一些缺点.

Can anyone share experience with unit testing views? I read a lot of tutorials about how to do unit testing with views, but everything has some drawbacks.

我采用了以下方法.它有效,但是我想知道是否有更好的方法可以做到这一点.还有一些缺点,我将在后面解释.我也在用量角器进行E2E测试,但是它们总是很慢,因此我将其限制在最低限度.

I came along with the following approach. It works, but I'm wondering if there is a better way to do this. There are also some drawbacks, which I'll explain later on. I'm also doing E2E tests with protractor, but they are always slow, and therefore I limit them to a minimum.

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

This is my controller. It has two variables bound to its $scope which are used in the view:

// 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指令:

The view takes the $scope.bar into a <span> and the $scope.jobs array into an ng-repeat directive:

<!-- 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.

In the beforeEach function, I'll set up the controller. The createController function (which is called from the tests itself) takes a view out of the $templateCache, creates a controller with it's own $scope, then it compiles the template and triggers a $digest.

模板缓存中预先装有karmas预处理程序ng-html2js

The template cache is prefilled with karmas preprocessor ng-html2js

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

使用这种方法,我有一个小问题,还有一些问题:

With this approach, I have a little problem, and some questions:

1. ng-repeat

1. Additional $$hashKey keys in my objects from ng-repeat

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

The expect($scope.jobs).toEqual([{name: "cook"}]); in my test throws an error:

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

我知道ng-repeat添加了这些键,但这很难测试.我能想到的唯一方法是分离控制器测试和视图测试.但是当我检查控制器内的jobs数组时,$$hashKey不存在.任何想法,为什么会这样?

I know that ng-repeat adds these keys, but this is silly to test. The only way around I can think of is separating the controller tests and the view tests. But when I check the jobs array inside my controller, the $$hashKey is not present. Any ideas, why this is happening?

2. $ scope问题

当我第一次尝试这样做时,我只将本地范围定义为$scope={},而不是$scope = $rootScope.$new(),就像我在其他控制器测试中所做的那样.但是只有一个普通对象作为局部作用域,我无法对其进行编译($compile(angular.element(html))($scope);引发了错误).

When I tried this for the first time, I only had my local scope defined as $scope={} and not $scope = $rootScope.$new(), as I have done in my other controller tests. But with just a plain object as a local scope, I wasn't able to compile it ($compile(angular.element(html))($scope); throwed an error).

我还认为将$rootScope本身作为控制器的当前本地范围是一个好主意.这是一个好方法吗?还是有什么缺点,我还没有看到?

I also thought if it is a good idea to pass the $rootScope itself as the current local scope for the controller. Is this a good approach? Or are there any drawbacks, I haven't seen yet?

3.最佳做法

我很高兴知道,其他人如何在AngularJS中进行单元测试.我认为必须对视图进行测试,因为在所有角度指令中都包含很多逻辑,如果看到这些逻辑,我将非常高兴;)

I would be very happy to know, how everyone else is doing unit tests in AngularJS. I think views have to be tested, because with all the angular directives, there lies a lot of logic in them, which I would be glad to see waterproofed ;)

推荐答案

我认为您正在做的是单元测试视图的好方法.对于您希望对测试视图进行单元化的人员,您问题中的代码是一个很好的秘诀.

I think that what you're doing is a great way to unit test views. The code in your question is a good recipe for someone looking to unit test views.

不用担心数据.相反,请测试各种操作的结果,因为这是您最终要真正关心的.因此,使用 jasmine-jquery 可以在创建控制器和模拟click()之后验证DOM的状态.等

Don't worry about the data. Instead, test the result of various operations, because that's what you really care about at the end of the day. So, use jasmine-jquery to verify the state of the DOM after creation of the controller, and after simulated click()s, etc.

$rootScope Scope 的实例,而$rootScope.$new()创建 ChildScope 的实例.从技术上讲,使用 ChildScope 实例进行测试更为正确,因为在生产环境中,控制器范围也是 ChildScope 的实例.

$rootScope is an instance of Scope, while $rootScope.$new() creates an instance of ChildScope. Testing with an instance of ChildScope is technically more correct because in production, controller scopes are instances of ChildScope as well.

顺便说一句,创建隔离范围的单元测试指令也是如此.当您使用 ChildScope 实例使用指令$compile时,将自动创建一个隔离范围(这是 Scope 的实例).您可以使用element.isolateScope()

BTW, the same goes for unit testing directives that create isolated scopes. When you $compile your directive with an instance of ChildScope an isolated scope will be created automatically(which is an instance of Scope). You can access that isolated scope with 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测试视图

有人说用量角器测试视图.当您要测试整个堆栈时,量角器非常有用:前端到后端.但是,量角器速度很慢,单元测试速度很快.这就是为什么通过模拟依赖于后端的应用程序的任何部分来使用单元测试来测试您的视图和指令是有意义的.


3. +1 Testing Views

Some people say test views with Protractor. Protractor is great when you want to test the entire stack: front end to back end. However, Protractor is slow, and unit testing is fast. That's why it makes sense to test your views and directives with unit tests by mocking out any part of the application that relies on the back-end.

指令是高度可单元测试的.控制器少了.控制器可能有很多活动部件,这会使它们更难测试.因此,我赞成经常创建指令.结果是模块化代码更易于测试.

Directives are highly unit testable. Controllers less so. Controllers can have a lot of moving parts and this can make them more difficult to test. For this reason, I am in favor of creating directives often. The result is more modular code that's easier to test.

这篇关于单元测试视图-最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆