【问题标题】:AngularJS- unit testing an anonymous controllerAngularJS- 对匿名控制器进行单元测试
【发布时间】:2014-10-24 15:01:57
【问题描述】:

我正在尝试为我没有编写的使用 ui-router 的代码编写测试。

我无法找到将控制器注入测试的方法,因为它是在另一个控制器中配置的状态内内联和匿名编写的:

$scope.deleteSomething = function() {
  $modal.open(
    templateUrl: '/delete-item-modal.html',
    controller: ['$scope', '$modalInstance', 'someService', 
      function($scope, $modalInstance, someService) {
        ....
      }
    ],
    resolve: {
      ...
    }
  });  
};

如果控制器被命名为 controller: 'TheController' 之类的名称,那么在我的测试中这样注入它就没有问题了:

beforeEach(inject(function($controller) {
  $controller('TheController', {/*dependancies to be injected*/});
}));

但由于控制器是匿名的,我没有它的句柄,也不知道如何访问它。

【问题讨论】:

  • 所以,你有答案:将控制器重构为命名控制器,使其可测试。
  • @Jb Nizet 是的,但我试图避免这种情况,因为它不是我的代码并且宁愿不重构它。那将是最后的手段。
  • 我知道这并不能解决你的问题,但如果不是你的代码,并且你不允许修改它,那么你不应该对它进行单元测试。编写代码的开发人员应该是测试它的人。
  • 我可以修改它,但想知道这是否有必要,因为重构它可能有潜在的陷阱。但总的来说,我同意编写代码的开发人员应该编写单元测试。我正在做一份交给我的工作。

标签: angularjs unit-testing angular-ui-router


【解决方案1】:

这是一个站不住脚的情况。您应该对准备修改的代码进行单元测试,以防止回归。如果您无法在当前状态下对其进行单元测试,那么您唯一的选择就是对其进行集成测试。 向请求工作的人解释:

  • 您必须在修改代码之前为其编写测试。
  • 集成测试需要更长的时间,但由于代码的结构,这是唯一可行的方法。
  • 通过提取命名控制器进行重构是一种复制粘贴,风险很低。
  • 可以轻松对命名控制器进行单元测试。

这就是我要做的。

【讨论】:

    【解决方案2】:

    您可以测试匿名控制器。您必须传递控制器构造函数数组本身,而不是将控制器标识符传递给 $controller(...) 函数。

    为此,您需要使单元测试代码可以访问控制器代码。这通常使用 JavaScript 的模块化工具(例如 Webpack)来完成。但它可以在您的测试配置和<script></script> 标签排序中完成。我建议使用工具。

    不管怎样,你最终会得到三个文件:

    // delete-item-controller.js
    
    DeleteItemController = ['$scope', '$modalInstance', 'someService', 
      function($scope, $modalInstance, someService) {
        ....
      }
    ];
    

    // state-controller.js
    
    $scope.deleteSomething = function() {
        $modal.open(
            templateUrl: '/delete-item-modal.html',
            controller: DeleteItemController,
            resolve: {
              ...
            }
        });  
    };
    

    // delete-item-controller.spec.js
    
    beforeEach(inject(function($controller) {
        $controller(DeleteItemController, {/*dependancies to be injected*/});
    }));
    

    替代示例,使用模块加载器

    使用 Webpack 看起来会有些不同......但它消除了持有 DeleteItemController 的 icky、隐含的全局对象。

    // delete-item-controller.js
    
    module.exports = ['$scope', '$modalInstance', 'someService', 
      function($scope, $modalInstance, someService) {
        ....
      }
    ];
    

    // state-controller.js
    
    var DeleteItemController = require("./delete-item-controller");
    
    $scope.deleteSomething = function() {
        $modal.open(
            templateUrl: '/delete-item-modal.html',
            controller: DeleteItemController,
            resolve: {
              ...
            }
        });  
    };
    

    // delete-item-controller.spec.js
    
    var DeleteItemController = require("./delete-item-controller");
    
    beforeEach(inject(function($controller) {
        $controller(DeleteItemController, {/*dependancies to be injected*/});
    }));
    

    【讨论】:

      猜你喜欢
      • 2013-05-01
      • 1970-01-01
      • 2016-02-12
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多