当前位置: 动力学知识库 > 问答 > 编程问答 >

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

问题描述:

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?

网友答案:

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 becomes 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 comments/answers.

网友答案:

I'm not sure to completely 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 recommend 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 comment of Claies.

分享给朋友:
您可能感兴趣的文章:
随机阅读: