【问题标题】:Issues unit testing controllerAs: logging controller returns a promise问题单元测试控制器作为:日志控制器返回一个承诺
【发布时间】:2016-03-27 22:23:33
【问题描述】:

我正在尝试测试一个使用 controllerAs 语法的控制器。我的问题是,当我尝试在控制器上测试一个函数时,我得到“预期未定义要定义”。

控制器(缩短版)

(function (angular) {
  'use strict';

  /* @ngInject */
  function PreflightCtrl($state, $window, $timeout, $stateParams, toastr, accountService, servicesService, geoService, visitService, localStorageService, Notifications, service, UTILS) {

    /* Exported Vars */
    var vm = this;

    /* Exported functions */
    vm.verifyDob = verifyDob;

    function verifyDob() {
      if (!vm.form.dob || (vm.form.dob.length !== 8 && vm.form.dob.length !== 10)){
        return;
      }
      if(vm.form.dob.length === 8){
        var lastTwoDigits = vm.form.dob.substr(vm.form.dob.length-2);
        if(lastTwoDigits === '19'){
          return;
        }
      }
      var dob = new Date(vm.form.dob);
      vm.verifyingDob = true;
      accountService.verifyDOB(dob)
        .success(function(data){
          vm.genderDisabled = false;
          vm.dobError = false;
          $timeout(function() {
            dobInput.blur();
          });
        })
        .error(function (status) {
          vm.genderDisabled = true;
          vm.dobError = true;
        })
        .finally(function () {
          vm.verifyingDob = false;
        });
    }
  }

  angular
    .module('app')
    .controller('PreflightCtrl', PreflightCtrl);

}(angular));

测试

describe('PreflightCtrl', function(){
  var PreflightCtrl, $state, $window, $timeout, $stateParams, toastr, accountService, servicesService, geoService, visitService, localStorageService, Notifications, service, UTILS, mockAccountService, mockServicesService;

  beforeEach(module('app'));

  beforeEach(inject(function($controller, _$state_, _$window_, _$timeout_, _$stateParams_, _toastr_, _accountService_, _servicesService_, _geoService_, _visitService_, _localStorageService_, _Notifications_, _UTILS_){

    //mock services used in PreflightCtrl
    mockAccountService = {
      verifyDOB: function verifyDOB(dob){
        return {
          success: function(callback){
            callback(dob);
          }
        }
      },
      isPermUser: function isPermUser(){
        return {
          success: function(callback){
            callback(true);
          }
        }
      },
      profile: {
        gender: 'male'
      }
    };

    mockServicesService = {
      isGenderAllowed: function isGenderAllowed(serviceCode, gender){
        return true;
      }
    }

    //prepare for dependency injection
    $state = _$state_;
    $window = _$window_;
    $timeout = _$timeout_;
    $stateParams = _$stateParams_;
    toastr = _toastr_;
    accountService = mockAccountService;
    servicesService = mockServicesService;
    geoService = _geoService_;
    visitService = _visitService_;
    localStorageService = _localStorageService_;
    Notifications = _Notifications_;
    service = {"id": 3, "code": "HL", "flags": {"multi_medicine": false}, "genders": ["male"], "name": "Hair Loss", "product": {"count": 3}, "visible": 1};
    UTILS = _UTILS_;

    //spy on the mocked services
    spyOn(accountService, 'verifyDOB').and.callThrough();
    spyOn(servicesService, 'isGenderAllowed').and.callThrough();

    //create the controller
    PreflightCtrl = $controller('PreflightCtrl', {
      $state: $state,
      $window: $window,
      $timeout: $timeout,
      $stateParams: $stateParams,
      toastr: toastr,
      accountService: accountService,
      servicesService: servicesService,
      geoService: geoService,
      visitService: visitService,
      localStorageService: localStorageService,
      Notifications: Notifications,
      service: service,
      UTILS: UTILS
    });

  }));

  it('should have a defined controller', function(){
    expect(PreflightCtrl).toBeDefined();
  });

  it('should have a defined function called verifyDob', function(){
    console.log(PreflightCtrl);
    expect(PreflightCtrl.verifyDob).toBeDefined();
  });

  it('should verify a DOB', function(){

    PreflightCtrl.form.dob = '01/01/1990';
    PreflightCtrl.verifyDob();
    expect(PreflightCtrl.verifyingDob).toBe(false);
  });
});

当我运行测试时,这是我得到的输出:

运行“业力:单位”(业力)任务 PhantomJS 1.9.8 (Mac OS X 0.0.0) 日志:'警告:尝试多次加载 angular。'

LOG: Promise{$$state: Object{status: 2, value: Error{message: ...}}} PhantomJS 1.9.8 (Mac OS X 0.0.0) PreflightCtrl 应该有一个名为 verifyDob FAILED 的定义函数 期望定义未定义。 在 /Users/tracy/Projects/LemonaidClinic/src/views/preflight/preflight.controller.spec.js:80 PhantomJS 1.9.8 (Mac OS X 0.0.0) PreflightCtrl 应该验证 DOB FAILED TypeError:“未定义”不是对象(评估“PreflightCtrl.form.dob = '01/01/1990'') 在 /Users/tracy/Projects/LemonaidClinic/src/views/preflight/preflight.controller.spec.js:85 PhantomJS 1.9.8 (Mac OS X 0.0.0):执行 15 次,共 15 次(2 次失败)(0.006 秒 / 0.204 秒) 警告:任务“业力:单位”失败。使用 --force 继续。

由于警告而中止。

第 80 行是这一行:expect(PreflightCtrl.verifyDob).toBeDefined();

第 85 行是这样的: PreflightCtrl.form.dob = '01/01/1990';

你可以看到第一行是控制器的日志,它返回一个承诺,这意味着控制器上没有需要存在的函数或变量。

我也不确定为什么 Angular 会尝试多次加载,但它似乎不会影响任何其他测试。

我做错了什么?

提前谢谢你。

【问题讨论】:

  • 我认为控制器在你调用 $rootScope.$apply() 之后才会存在。此外,您不需要手动注入每个依赖项。如果您没有在测试中自定义/覆盖它们,Angular 将注入它拥有的那些。
  • 我应该在哪里添加 $rootScope.$apply()?我手动创建的唯一依赖项是在我运行测试时导致错误的依赖项,并且创建这些模拟依赖项可以修复这些错误,所以我认为它们是必要的......

标签: angularjs unit-testing jasmine angularjs-controlleras


【解决方案1】:

我会更喜欢这样:

var 范围 = $rootScope.$new(); $controller('myController as vm', {$scope:scope, /*你的依赖树地狱*/}); $rootScope.$apply(); vm = scope.vm;//这是你的新控制器,你可以在测试中参考它。

我认为你必须模拟这么多的事实说明你的控制器有太多的依赖,直接和/或间接。

但是,如果您无法解决此问题,您可以通过创建一个名为“mocks”的文件夹并放入与真实文件具有相同 ID 的文件并将 Karma 指向该文件夹来更轻松地进行模拟.这些将覆盖实际的依赖关系。不利的一面是,如果您需要与注册的模拟不同的东西,您仍然需要进行一次性模拟,但它消除了必须在每次测试中设置模拟的任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-26
    • 2015-03-15
    • 1970-01-01
    • 2016-07-25
    • 2014-06-04
    • 1970-01-01
    • 2016-07-27
    • 2014-01-15
    相关资源
    最近更新 更多