最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Testing non-scope functions in Angular Controller with Jasmine - Stack Overflow

programmeradmin3浏览0评论

Jasmine is one of the most widely used testing frameworks to unit-test javascript code in BDD manner. I tried to use it for AngularJS ponents testing. AngularJS documentation provides the following sample code

describe('PasswordController', function() {
  beforeEach(module('app'));
  var $controller;

  beforeEach(inject(function(_$controller_){
    $controller = _$controller_;
  }));

  describe('$scope.grade', function() {
    it('sets the strength to "strong" if the password length is >8 chars', function() {
      var $scope = {};
      var controller = $controller('PasswordController', { $scope: $scope });
      $scope.password = 'longerthaneightchars';
      $scope.grade();
      expect($scope.strength).toEqual('strong');
    });
  });
});

So the code above uses angular mock library and via dependency injection processes a scope through a controller. Now I have a scope object with functions and objects my controller assigned to it. I can test it well. Happy.

Now the interesting part is if I want to test the functions which are not linked to the scope. For example, the doSomethingVeryCoolThatNeedsTesting function below

angular.module('app', [])
.controller('PasswordController', function PasswordController($scope) {
  $scope.password = '';
  $scope.grade = function() {
    var size = $scope.password.length;
    if (size > 8) {
      $scope.strength = 'strong';
    } else if (size > 3) {
      $scope.strength = 'medium';
    } else {
      $scope.strength = 'weak';
    }

   function doSomethingVeryCoolThatNeedsTesting() {
    ....  
   }

  };
});

It seems that whenever I use $controller('PasswordController', { $scope: $scope }); it returns a populated $scope object and undefined controller object.

TL;DR

Is there a way I can test Angular Controller functions which are not linked to the scope?

Jasmine is one of the most widely used testing frameworks to unit-test javascript code in BDD manner. I tried to use it for AngularJS ponents testing. AngularJS documentation provides the following sample code

describe('PasswordController', function() {
  beforeEach(module('app'));
  var $controller;

  beforeEach(inject(function(_$controller_){
    $controller = _$controller_;
  }));

  describe('$scope.grade', function() {
    it('sets the strength to "strong" if the password length is >8 chars', function() {
      var $scope = {};
      var controller = $controller('PasswordController', { $scope: $scope });
      $scope.password = 'longerthaneightchars';
      $scope.grade();
      expect($scope.strength).toEqual('strong');
    });
  });
});

So the code above uses angular mock library and via dependency injection processes a scope through a controller. Now I have a scope object with functions and objects my controller assigned to it. I can test it well. Happy.

Now the interesting part is if I want to test the functions which are not linked to the scope. For example, the doSomethingVeryCoolThatNeedsTesting function below

angular.module('app', [])
.controller('PasswordController', function PasswordController($scope) {
  $scope.password = '';
  $scope.grade = function() {
    var size = $scope.password.length;
    if (size > 8) {
      $scope.strength = 'strong';
    } else if (size > 3) {
      $scope.strength = 'medium';
    } else {
      $scope.strength = 'weak';
    }

   function doSomethingVeryCoolThatNeedsTesting() {
    ....  
   }

  };
});

It seems that whenever I use $controller('PasswordController', { $scope: $scope }); it returns a populated $scope object and undefined controller object.

TL;DR

Is there a way I can test Angular Controller functions which are not linked to the scope?

Share Improve this question asked Jul 1, 2015 at 10:14 Arturs VancansArturs Vancans 4,64014 gold badges49 silver badges79 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

No. As far as you don't expose the inner controller functions to the outside world those functions are private see the revealing module pattern.

So the problem is not angular neither the testing framework, The problem is the javascript language itself.

If you want to test an inner function you have to make it visible to the outside. The options are:

  1. Exposed it on the $scope object
  2. Expose onto any other global object which is strongly discouraged and might be not reachable by the test

i would choose one of those solutions:

  1. if it's a private function, maybe it should not be tested directly but rather through public api
  2. if it's an utility function then maybe it should be in its own controller/service as a public api

otherwise you have to pollute your controller api. i advise not to. sooner or later one of the developers will start to use this semi-hidden function

发布评论

评论列表(0)

  1. 暂无评论