Angular 中的单元测试指令控制器而不使控制器全局化 [英] Unit-testing directive controllers in Angular without making controller global

查看:32
本文介绍了Angular 中的单元测试指令控制器而不使控制器全局化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Vojta Jina 的优秀存储库中,他演示了指令测试,他在模块包装器之外定义了指令控制器.看这里:https://github.com/vojtajina/ng-directive-testing/blob/master/js/tabs.js

这不是不好的做法并污染全局命名空间吗?

如果在另一个地方调用 TabsController 可能是合乎逻辑的,那会不会破坏一些东西?

可在此处找到上述指令的测试:https://github.com/vojtajina/ng-directive-testing/commit/test-controller

是否可以将指令控制器与指令的其余部分分开测试,而不将控制器放在全局命名空间中?

最好将整个指令封装在 app.directive(...) 定义中.

解决方案

很好的问题!

因此,这是一个普遍关注的问题,不仅对于控制器,而且对于指令可能需要执行其工作但不一定要将此控制器/服务暴露给外部世界"的服务也可能存在.

我坚信全局数据是邪恶的,应该避免,这也适用于指令控制器.如果我们采用这个假设,我们可以采用几种不同的方法来本地"定义这些控制器.这样做时,我们需要记住控制器应该仍然容易"被单元测试访问,所以我们不能简单地将它隐藏在指令的闭包中.IMO 的可能性是:

1) 首先,我们可以简单地在模块级别定义指令的控制器,例如::

angular.module('ui.bootstrap.tabs', []).controller('TabsController', ['$scope', '$element', function($scope, $element) {...}]).directive('tabs', function() {返回 {限制:'EA',转置:真实,范围: {},控制器:'TabsController',templateUrl: 'template/tabs/tabs.html',替换:真};})

这是我们在 https://github 中使用的一种简单技术.com/angular-ui/bootstrap/blob/master/src/tabs/tabs.js 基于 Vojta 的工作.

虽然这是一种非常简单的技术,但应该注意的是,控制器仍然暴露给整个应用程序,这意味着其他模块可能会覆盖它.从这个意义上说,它使控制器成为 AngularJS 应用程序的本地控制器(因此不会污染全局窗口范围),但它也是所有 AngularJS 模块的全局控制器.

2) 使用封闭范围和特殊文件设置进行测试.

如果我们想完全隐藏一个控制器函数,我们可以将代码包装在一个闭包中.这是 AngularJS 正在使用的一种技术.例如,查看 NgModelController 我们可以看到它在自己的文件中被定义为一个全局"函数(因此很容易被测试访问),但整个文件在构建期间被包裹在闭包中:

总而言之:选项(2)更安全",但需要为构建进行一些前期设置.

In Vojta Jina's excellent repository where he demonstrates testing of directives, he defines the directive controller outside of the module wrapper. See here: https://github.com/vojtajina/ng-directive-testing/blob/master/js/tabs.js

Isn't that bad practice and pollute the global namespace?

If one were to have another place where it might be logical to call something TabsController, wouldn't that break stuff?

The tests for the mentioned directive is to be found here: https://github.com/vojtajina/ng-directive-testing/commit/test-controller

Is it possible to test directive controllers separate from the rest of the directive, without placing the controller in a global namespace?

It would be nice to encapsulate the whole directive within the app.directive(...) definition.

解决方案

Excellent question!

So, this is a common concern, not only with controllers but also potentially with services that a directive might need to perform its job but don't necessarily want to expose this controller / service to the "external world".

I strongly believe that global data are evil and should be avoided and this applies to directive controllers as well. If we take this assumption we can take several different approaches to define those controllers "locally". While doing so we need to keep in mind that a controller should be still "easily" accessible to unit tests so we can't simply hide it into directive's closure. IMO possibilities are:

1) Firstly, we could simply define directive's controller on a module level, ex::

angular.module('ui.bootstrap.tabs', [])
  .controller('TabsController', ['$scope', '$element', function($scope, $element) {
    ...
  }])
 .directive('tabs', function() {
  return {
    restrict: 'EA',
    transclude: true,
    scope: {},
    controller: 'TabsController',
    templateUrl: 'template/tabs/tabs.html',
    replace: true
  };
})

This is a simple technique that we are using in https://github.com/angular-ui/bootstrap/blob/master/src/tabs/tabs.js which is based on Vojta's work.

While this is a very simple technique it should be noted that a controller is still exposed to the whole application which means that other module could potentially override it. In this sense it makes a controller local to AngularJS application (so not polluting a global window scope) but it also global to all AngularJS modules.

2) Use a closure scope and special files setup for testing.

If we want to completely hide a controller function we can wrap code in a closure. This is a technique that AngularJS is using. For example, looking at the NgModelController we can see that it is defined as a "global" function in its own files (and thus easily accessible for testing) but the whole file is wrapped in closure during the build time:

To sum up: the option (2) is "safer" but requires a bit of up-front setup for the build.

这篇关于Angular 中的单元测试指令控制器而不使控制器全局化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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