GVKun编程网logo

在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器(angular单元测试怎么做)

17

这篇文章主要围绕在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器和angular单元测试怎么做展开,旨在为您提供一份详细的参考资料。我们将全面介绍在Angular中进行单元测试指令

这篇文章主要围绕在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器angular单元测试怎么做展开,旨在为您提供一份详细的参考资料。我们将全面介绍在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器的优缺点,解答angular单元测试怎么做的相关问题,同时也会为您带来Angular.js最佳实践-扩展控制器,覆盖控制器默认值、angularjs – $控制器服务在加载控制器时抛出错误、angularjs – Angular ui.router,从子控制器调用父控制器函数?、angularjs – Angular – 在子指令的控制器中获取父指令的控制器(不是链接函数)的实用方法。

本文目录一览:

在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器(angular单元测试怎么做)

在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器(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(…)定义中会很好。

答案1

小编典典

很好的问题!

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

我坚信 全局数据是有害的,应避免使用,这也适用于指令控制器
。如果采用这种假设,我们可以采用几种不同的方法来“本地”定义那些控制器。在这样做的时候,我们需要记住, 控制器应该仍然可以“轻松”地用于单元测试,
因此我们不能简单地将其隐藏在指令的闭包中。IMO的可能性是:

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

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  };})

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

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

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

如果要完全隐藏控制器功能,可以将代码包装在闭包中。这是AngularJS使用的技术。例如,查看NgModelController,我们可以看到它在自己的文件中被定义为“全局”函数(因此可以轻松地进行测试),但是整个文件在构建期间都被封装在闭包中:

  • https://github.com/angular/angular.js/blob/master/src/angular.prefix
  • https://github.com/angular/angular.js/blob/master/src/angular.suffix

综上所述:选项(2)比较“安全”,但是需要一些先期的构建步骤。

Angular.js最佳实践-扩展控制器,覆盖控制器默认值

Angular.js最佳实践-扩展控制器,覆盖控制器默认值

这是一个现实的Angular问题,我无法解决。我喜欢Angular,但是这个问题现在困扰着我很多。

扩展现有控制器功能,并在应用程序的另一页上使用扩展控制器的最佳实践是什么?换句话说: 如何在Angular中继承控制器?

编辑 -2014年9月23日,不要以为我的原始用例的描述会帮助访问者更好地理解我在这里的用意。我认为这使人们偏离了真正的问题。

答案1

小编典典

半年后,我想我完全了解发生了什么。正如对这篇文章的评论中指出的那样,最简单的答案是服务。

在最佳情况下,所有范围变量都是从工厂/服务收集的值。不过,您可能仍想使用具有一个额外功能的完全相同的控制器:$
scope.someFunction(){},并保留其余功能。在这种情况下,您确实有一个“薄”的控制器逻辑,这是理想的控制器设计-
但可能仍然会导致一百或更多行代码。您不希望在其他控制器中重复该操作,只是因为您需要一些额外的控制器逻辑(例如$ scope.someFunction())

那你怎么办呢?

答案是这样的:

  1. 确保您已尽力解决工厂问题
  2. 如果绝对确定已完成,请进行控制器注入:
        .controller(''childController'', function ($scope, $controller) {      ''use strict'';      $controller(''parentController'', {$scope: $scope});      $scope.someFunction=function(){}    })

就这么简单。-同样,通常情况下,工厂可以解决问题。

希望你觉得这个有用 ;)

angularjs – $控制器服务在加载控制器时抛出错误

angularjs – $控制器服务在加载控制器时抛出错误

我使用角度1.5.8.这是我的代码:
describe('My Controller',function() {
    var MyController;
    var $controller;
    var $rootScope;
    var $state;

    beforeEach(angular.mock.module('ui.router'));
    beforeEach(module('app.my.ctrl'));
    beforeEach(inject(function(_$controller_,_$rootScope_,_$state_) {
        $controller = _$controller_;
        $rootScope = _$rootScope_;
        $state = _$state_;
        MyController = $controller('MyController',{ scope: $rootScope.$new() });
    }));

    describe('#init',function() {
        it('should do something',function() {
            console.log('logStatement',MyController);

            MyController.init();

            expect(true).toBe(true);
        })

    })
});

测试运行器能够找到所有文件,所以这不是一个忘记加载的东西的情况.当我运行这个测试,不仅logStatement不会出现,我得到这个错误:

Argument 'MyController' is not a function,got undefined

这是我的控制器

(function() {
'use strict';

angular
    .module('app.my.ctrl')
    .controller('MyController',MyController);

MyController.$inject = [
    '$scope'
];
/* ngInject */
function MyController($scope) {

    var vm = this;

    vm.hello = 'world';

    vm.init = function() {
        return true;
    }
}

})();

这是我的业务conf文件:

// Karma configuration

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files,exclude)
    basePath: '',// frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],// list of files / patterns to load in the browser
    files: [
      'bower_components/angular/angular.js','bower_components/angular-mocks/angular-mocks.js','bower_components/angular-ui-router/release/angular-ui-router.js','src/controllers/MyController.js','tests/unit/**/*.spec.js',],// list of files to exclude
    exclude: [
      '**/*.swp'
    ],// preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },// test results reporter to use
    // possible values: 'dots','progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['spec'],//  Spec Reporter Config
    specReporter: {
    //     suppressErrorSummary: false,//     suppressFailed: false,//     suppresspassed: false,suppressSkipped: true
    //     showSpecTiming: false
    },// web server port
    port: 9876,// enable / disable colors in the output (reporters and logs)
    colors: true,// level of logging
    // possible values: config.LOG_disABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,// enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,// start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],// Continuous Integration mode
    // if true,Karma captures browsers,runs the tests and exits
    singleRun: true,// Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
};

这是什么意思??我在文档中找不到任何解释这一点的东西.

更新:

我已经读了this answer,答案没有奏效.

尝试将控制器中注入的服务从范围更改为范围
beforeEach(inject(function(_$controller_,_$state_) {
      $controller = _$controller_;
      $rootScope = _$rootScope_;
      $state = _$state_;
      MyController = $controller('MyController',{ $scope: $rootScope.$new()});
}));

angularjs – Angular ui.router,从子控制器调用父控制器函数?

angularjs – Angular ui.router,从子控制器调用父控制器函数?

我使用Angular与ui.router并设置了嵌套视图.父视图有一个div,其可见性可以通过父控制器上的函数切换.我想从嵌套视图的子控制器调用此函数.我该怎么做?
http://plnkr.co/edit/zw5WJVhr7OKqACoJhDZw?p=preview

JS

// Code goes here

angular.module("myApp",[]).controller("parent",function($scope){
  $scope.parentFunction = function(){
    alert("Called a function on the parent")
  }  
}).controller("child",function($scope){
  $scope.childFunction = function(){
    alert("Called a function on the child")
  }

  $scope.parentFromChild = function(){
    alert("I kNow this feels weird");
    $scope.parentFunction();
  }
})

HTML

<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.2.14" src="http://code.angularjs.org/1.2.14/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="myApp">
    <div ng-controller="parent">
      <div ng-controller="child">
        <a href="#" ng-click="parentFunction()">Call Parent</a>
        <a href="#" ng-click="childFunction()">Call Child</a>
        <a href="#" ng-click="parentFromChild()">Call Parent from Child</a>
      </div>
    </div>
  </body>

</html>

控制器上的范围是原型继承的,我相信这意味着如果您不重新定义范围上的函数,从父范围获得相同的函数(如果您调用它)(问题是这样做就假定使用的上下文的控制器,虽然这是有争议的,如果这真的是一个问题,假设你不依赖于该控制器中的某些效果).

angularjs – Angular – 在子指令的控制器中获取父指令的控制器(不是链接函数)

angularjs – Angular – 在子指令的控制器中获取父指令的控制器(不是链接函数)

我知道如何在子指令的link函数中获取parent的指令控制器.
但是,我宁愿避免使用链接函数(和$scope all-together)并将所有代码都放在指令的控制器函数下.
angular.directive('parent',function(){
    return {
        templateUrl: '/parent.html',scope: true,bindToController: true,controllerAs: 'parentCtrl',controller: function(){
            this.coolFunction = function(){
                console.log('cool');
            }
        }
    }
});

angular.directive('child',function(){
    return {
        templateUrl: '/child.html',require: '^parent',controllerAs: 'childCtrl',controller: function() {
            // I want to run coolFunction here.
            // How do I do it?
        }
    }
});

任何帮助表示赞赏!

您可以将’$element’注入控制器并访问父控制器,如 –
controller: ($element) ->
    var parentCtrl = $element.parent().controller('parent');
    parentCtrl.coolFunction();
    //..........
    //..........

这可能不是访问“任何”父控制器最透明的方式,因为它需要指令的特定名称,它是jqlite而不是纯Angular.

发现这个帖子很有用 – How to access parent directive’s controller by requiring it recursively?

编辑:感谢@Dmitry弄清楚角度不需要’.parent’来获得控制器.更新的代码 –

controller: ($element) ->
    var parentCtrl = $element.controller('parent');
    parentCtrl.coolFunction();
    //..........

关于在Angular中进行单元测试指令控制器而无需使控制器成为全局控制器angular单元测试怎么做的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于Angular.js最佳实践-扩展控制器,覆盖控制器默认值、angularjs – $控制器服务在加载控制器时抛出错误、angularjs – Angular ui.router,从子控制器调用父控制器函数?、angularjs – Angular – 在子指令的控制器中获取父指令的控制器(不是链接函数)等相关内容,可以在本站寻找。

本文标签: