在AngularJS中具有Controller的单元测试指令

时间:2014-01-17 16:14:01

标签: unit-testing angularjs

我正在开发一个AngularJS应用程序。我希望能够通过这个应用程序实现单元测试。目前,我正在努力对我的一个指令进行单元测试。这时,我有一个模块设置如下:

angular.module('my.module', [])
  .controller('myCtrl', function ($scope, $element) {
    // Directive specific business logic goes here
  })
  .directive('myDirective', function() {
    return {
      restrict: 'E',
      transclude: true,
      replace: true,
      scope: {
        title:'=',
    state:'@'
      },
      templateUrl: 'myHtml.tpl.html',
      controller: myCtrl
    };
  })
;

我已将控制器从我的指令中分离出来,因为我需要能够对控制器进行单元测试。此代码适用于应用程序本身。但是,当我尝试对其进行单元测试时,我遇到了问题。我遇到问题,因为我无法弄清楚如何从单元测试中将$元素注入控制器。目前,我有以下测试设置:

describe('my.module', function () {
    var $scope;
    var myCtrl;

    beforeEach(module('myApp'));
    beforeEach(inject(function ($controller, $rootScope, $element) {
        $scope = $rootScope.$new();
        myCtrl = $controller('myCtrl', { $scope: $scope });
    }));

    it('should create controller', inject(function () {
      expect(testCtrl).toBeDefined();
    }));

    it('should create the directive', inject(function ($rootScope, $compile, $log) {
      var d = angular.element('<my-directive></my-directive>');
      $compile(d)($rootScope);
      $scope.$digest();

      expect($log.assertEmpty).not.toThrow();
    }));
});

$ element是自动注入指令的东西。但是,我无法弄清楚如何将其注入控制器。我需要这样做,所以我可以进行单元测试。我该怎么做?

谢谢!

2 个答案:

答案 0 :(得分:2)

我可以在控制器的单元测试中推荐的只是担心控制器暴露的逻辑。您正试图在控制器测试中测试指令的逻辑,即通过$element

在控制器测试中模拟它,因为元素可以是任何东西。你的控制器不应该关心DOM;它是一个控制器,它的主要(也许只是)工作是创建一个范围并向范围公开“事物” - 函数,变量,逻辑。它们不应该与指令的逻辑绑定,否则耦合太紧。控制器应该能够自由地接收输入, 的正确输入,并使用输入来回馈输出。

如果您可以举例说明您的控制器公开的逻辑,那么我可以进一步帮助编写单元测试。

更新

现在查看您提供的单元测试。您需要将逻辑从控制器和指令的单元测试中分离出来。

答案 1 :(得分:1)

用于注入$element$log按原样执行:

describe('my.module', function ($compile) {
    var $scope, $controller, $element, $log, $compile, html;

    beforeEach(module('myApp'));
    // an another module ...

    beforeEach(inject(function ($injector) {
       $scope = $injector.get('$rootScope');
       $controller = $injector.get('$controller');
       $element = $injector.get('$element');
       $log = $injector.get('$log');
       $compile = $injector.get('$compile');

       function createController (){
          return $controller('MyCtrl', {'$scope' : $scope, '$element' : $element, '$log': $log });
       }
       // init your controller
       createController();

    }));

    it('should create the directive',function () {
    // possibility to use $scope, $element, $log in your test
      $compile('<my-directive></my-directive>')($scope);
      $scope.$digest();

      expect($log.assertEmpty).not.toThrow();
    });
});