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

javascript - How to create unit-testing for array function in AngularJS with Jasmine - Stack Overflow

programmeradmin2浏览0评论

I have xf array: var xf = []; And I have a function is a element in this array and a function to use it:

$scope.checkEmailValid = function () {
  var result = false;
  Iif (xf.validateEmail($scope.email, '256')) {
    result = true;
  }
  return result;
};

xf.validateUsername = function (sText) {
  var isValid = false;
  do {
    //Check for valid string.
    isValid = typeof sText === 'string';
    if (!isValid) {
      break;
    }
    //Check that each special character does not exist in string.
    for (var i = 0; i < sText.length; i++) {
      if (xf.SPECIAL_CHARS.indexOf(sText.charAt(i)) !== -1) {
        isValid = false;
        break;
      }
    }
    if (!isValid) {
      break;
    }
  } while (false);
  return isValid;
};

But when I run my spec:

it ('checkEmail', function(){
  $controller('MyCtrl', { $scope: $scope });
  xf.validateUsername();
  spyOn(window,xf.validateUsername).and.callThrough();
});

It makes an error:

xf.validateUsername is not a function

How can I cover it?

I have xf array: var xf = []; And I have a function is a element in this array and a function to use it:

$scope.checkEmailValid = function () {
  var result = false;
  Iif (xf.validateEmail($scope.email, '256')) {
    result = true;
  }
  return result;
};

xf.validateUsername = function (sText) {
  var isValid = false;
  do {
    //Check for valid string.
    isValid = typeof sText === 'string';
    if (!isValid) {
      break;
    }
    //Check that each special character does not exist in string.
    for (var i = 0; i < sText.length; i++) {
      if (xf.SPECIAL_CHARS.indexOf(sText.charAt(i)) !== -1) {
        isValid = false;
        break;
      }
    }
    if (!isValid) {
      break;
    }
  } while (false);
  return isValid;
};

But when I run my spec:

it ('checkEmail', function(){
  $controller('MyCtrl', { $scope: $scope });
  xf.validateUsername();
  spyOn(window,xf.validateUsername).and.callThrough();
});

It makes an error:

xf.validateUsername is not a function

How can I cover it?

Share Improve this question edited Apr 1, 2016 at 11:11 Sergey Weiss 5,9748 gold badges32 silver badges40 bronze badges asked Jul 31, 2015 at 10:14 Pham Minh TanPham Minh Tan 2,0967 gold badges27 silver badges39 bronze badges 3
  • is xf a property on $scope, a property on the controller, or just some free-form variable in the controller function body? – Claies Commented Aug 3, 2015 at 4:38
  • @Claies: xf is just a free-form variable in the controller body. – Pham Minh Tan Commented Aug 3, 2015 at 6:40
  • 1 it's not really possible to test this in that manner. If it is not actually bound to $scope or exposed as a public property, it is only accessible in the function that it is defined, due to the way that JavaScript closures operate. – Claies Commented Aug 3, 2015 at 16:10
Add a ment  | 

4 Answers 4

Reset to default 1

The xf variable is not acessible from the outside of the controller's scope (i.e. not accessible in the unit test files).

You must've done the following thing:

angular
  .module('myModule')
  .controller(function ($scope) {
    var xf = [];
    // etc.
  });

You could attach the xf variable to the MyController instance once Angular instantiates it:

angular
  .module('myModule')
  .controller(function ($scope) {
    this.xf = [];
    // etc.
  });

But that's not really a clean way of doing it. A better way (in my opinion) would be to create a factory:

angular
  .module('myModule')
  .factory('xfService', function () {
    var xf = [];

    function validateUsername(text) {
      // etc.
    }

    function get() {
      return xf;
    }

    return {
      get: get,
      validateUsername: validateUsername
    };
  });

Now, you can inject the factory in your controller to use xf:

angular
  .module('myModule')
  .controller(function ($scope, xfService) {
    // somewhere
    var isValid = xfService.validateEmail($scope.email, '256');
    // to get the values in the array
    var values = xfService.get();
  });

Finally, for the unit tests, it bees really easy to test the validateEmail method.

describe('Unit tests - xfService', function () {
  var xfService;
  beforeEach(angular.module('myModule'));
  beforeEach(angular.inject(function (_xfService_) {
      xfService = _xfService_;
    });
  });

  describe('xfService.validateUsername', function () {
    it('should return a boolean value', function () {
      // for example
      expect(typeof xfService.validateUsername('test')).toBe('boolean');
    });
    // add more unit tests to check that the method works as expected
  });
});

You'll need to add the angular-mocks file to the Karma config.

Thanks to Paul Podlech and Claies for the hints in the ments/answers.

I'm not sure to pletely understand your question. But there are a few thinks i think you are doing wrong:

  • If xf it's a global variable you should mock it, since you are testing the controller, not the global variable.
  • If you want to check the real function of your global variable, go to the karma.conf.js file and add the js file path to the files option:

    files: [ ..., 'fx-script.js', ... ],

  • callThrough should be used before the actual function is invoked:

    it ('checkEmail', function(){ var ctrl = $controller('MyCtrl', { $scope: $scope }); spyOn(window, ctrl.xf.validateUsername).and.callThrough(); ctrl.xf.validateUsername(); });

I remend you to separately test your controller, service, or global scripts, and add mocks whenever you need to inject a dependency or global variable, so if you can tell for sure which module/script is failing any time.

you should move functionality in xf into separate service/factory. Then inject it in controller. That makes it pretty easy to mock it while testing.

Try this in the controller

var xf = this.xf = [];

and this in your test

it ('checkEmail', function(){
 var xf = $controller('MyCtrl', { $scope: $scope }).xf;
 spyOn(xf, 'validateUsername').and.callThrough();
 xf.validateUsername();
});

But you should realize that this exposes your xf object on the Controller as mentioned in the ment of Claies.

发布评论

评论列表(0)

  1. 暂无评论