简体   繁体   English

如何使用Jasmine在AngularJS中为数组函数创建单元测试

[英]How to create unit-testing for array function in AngularJS with Jasmine

I have xf array: var xf = []; 我有xf数组: 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 xf.validateUsername不是函数

How can I cover it? 我该如何掩饰?

The xf variable is not acessible from the outside of the controller's scope (ie not accessible in the unit test files). xf变量在控制器范围之外是不可取的(即,在单元测试文件中不可访问)。

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实例化后将xf变量附加到MyController实例:

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: 现在,您可以将工厂注入控制器以使用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. 最后,对于单元测试,测试validateEmail方法变得非常容易。

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. 您需要将angular-mocks文件添加到Karma配置中。

Thanks to Paul Podlech and Claies for the hints in the comments/answers. 感谢Paul Podlech和Claies在评论/答案中的提示。

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. 如果xf是全局变量,则应该模拟它,因为您正在测试控制器,而不是全局变量。
  • 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: 如果要检查全局变量的实函数,请转到karma.conf.js文件,并将js文件路径添加到files选项:

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

  • callThrough should be used before the actual function is invoked: 应该在调用实际函数之前使用callThrough

    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. 我建议您分别测试controllerservice或全局脚本,并在需要注入依赖项或全局变量时添加module ,以便您可以随时确定哪个module / script失败。

you should move functionality in xf into separate service/factory. 您应该将xf中的功能移到单独的服务/工厂中。 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 . 但是您应该意识到,这正如Claies的评论中提到的那样,将xf对象暴露在Controller上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM