【问题标题】:Angular Unit Testing Factory InjectionAngular 单元测试工厂注入
【发布时间】:2016-10-25 19:26:59
【问题描述】:

我已经看到了这个答案,但没有一个解决方案对我有用。我收到一个错误Error: [ng:areq] Argument 'fn' is not a function, got undefined,这导致我的测试失败。将工厂注入不是存根工厂的测试规范的正确方法是什么。

登录模块

angular.module('loginModule', ['ui.bootstrap', 'permission', 'ui.router', 'coreModule', 'utilsModule']);

登录控制器

  (function(){
      'use strict';

      angular.module('loginModule')
      .controller('loginController', login);

      login.$inject = [
          '$log',
          '$uibModal',
          '$rootScope',
          'storageFactory',
          'loginFactory',
          '$state',
          'RoleStore',
          'PermissionStore',
          'vsmsCoreFactory'
      ];

      function login($log, $uibModal, $rootScope, storageFactory, loginFactory, $state, RoleStore, PermissionStore, vsmsCoreFactory) {

          /* jshint validthis: true */
          var vm = this;
          vm.loginUser = loginUser;
          vm.forgotPassword = forgotPassword;
          vm.errorCode = null;
          PermissionStore.clearStore();
          vsmsCoreFactory.getHashFunction()
            .then(function(response) {
                if(response) {
                  storageFactory.setHashFunction(response); // unknown provider
              }
            });

          function loginUser() {
          ...

登录控制器规范

describe('loginController', function() {

  var $controller;

  beforeEach(module('loginModule'));

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

  describe('vm.loginUser', function() {
    it('should be defined', function() {
      var loginController = $controller('loginController');
      expect(loginController.loginUser).toBeDefined();
    });
  });

});

单元测试文件

'use strict';

var gulp = require('gulp');

var $ = require('gulp-load-plugins')();

var wiredep = require('wiredep');

var paths = gulp.paths;

function runTests (singleRun, done) {
  var bowerDeps = wiredep({
    directory: 'bower_components',
    exclude: ['bootstrap-sass-official'],
    dependencies: true,
    devDependencies: true
  });

  var testFiles = bowerDeps.js.concat([
    './src/components/scripts/ui-bootstrap-custom-tpls-2.1.3.js',
    './src/app/index.js',
    './src/{app,components}/**/*.module.js',
    './src/{app,components}/**/*.factory.js',
    './src/{app,components}/**/*.controller.js',
    './src/{app,components}/**/*.spec.js'
  ]);

  gulp.src(testFiles)
    .pipe($.karma({
      configFile: 'karma.conf.js',
      action: (singleRun)? 'run': 'watch'
    }))
    .on('error', function (err) {
      // Make sure failed tests cause gulp to exit non-zero
      throw err;
    });
}

gulp.task('test', function (done) { runTests(true /* singleRun */, done) });
gulp.task('test:auto', function (done) { runTests(false /* singleRun */, done) });

应用程序

'use strict';

angular.module('fotaAdminPortal',
    [
    'ngAnimate',
    'ngCookies',
    'ngTouch',
    'ngSanitize',
    'ngResource',
    'ui.bootstrap',
    'ui.router',
    'ui.router.stateHelper',
    'pascalprecht.translate',
    'utilsModule',
    'loginModule',
    ...
    ])

日志

Chrome 54.0.2840 (Mac OS X 10.11.6) loginController vm.loginUser 应该定义为 FAILED 错误:[$injector:unpr] 未知提供者:storageFactoryProvider

【问题讨论】:

    标签: angularjs unit-testing karma-jasmine


    【解决方案1】:

    fotaAdminPortal 模块没有为测试加载,所以vsmsCoreFactory 永远不会被注册。

    此外,无需手动将服务传递给控制器​​,因为注入器会在您创建它时自动执行此操作。当您需要传递不是全局注册服务(即$scope)或模拟单个控制器实例的服务时,手动传递服务很有用。

    Atm 工厂的模拟只是一个未定义的变量,当依赖于它们的逻辑尝试调用不存在的方法时会导致错误。您需要在这些模拟上正确地存根任何方法。但是暂时把这些放在一边,你的测试应该是这样的:

    describe('loginController', function() {
    
      var $controller;
    
      beforeEach(module('fotaAdminPortal'));
    
      beforeEach(inject(function(_$controller_){
        $controller = _$controller_;
      }));
    
      describe('vm.loginUser', function() {
          it('should be defined', function() {
            var loginController = $controller('loginController');
            expect(loginController.loginUser).toBeDefined();
          });
      });
    
    });
    

    如果您想单独加载loginModule,则需要将vsmsCoreFactory 提取到另一个模块中并将其添加为依赖项:

    angular.module('vsmsCore', [])
      .factory('vsmsCoreFactory', function($http, env, $log, storageFactory) {
    
      });
    
    angular.module('loginModule', ['ui.bootstrap', 'permission', 'ui.router', 'vsmsCore']);
    

    那你可以改用beforeEach(module('loginModule'))

    【讨论】:

    • fotaAdminPortal是主app模块,由karma('./src/app/index.js')和vsmsCoreFactory('./src/{app ,components}/**/*.factory.js'),如单元测试文件中所示。业力日志还显示应用程序文件和工厂都已加载。 loginModulefotaAdminPortal 的依赖项。
    • 文件已加载,但除非您使用module(..) 启动模块,否则它永远不会注册。问题是 loginModule 依赖于父模块的服务 (vsmsCoreFactory),因此它是紧密耦合的,不能单独创建。要么启动整个应用程序,要么将服务提取到单独的模块中,并将其作为依赖项添加到 loginModule
    • 好的,有道理。我为工厂创建了一个coreModule,并将其添加为loginModule 的依赖项,从而解决了vsmsCoreFactory 未定义的问题。现在,我看到了未知的提供者: storageFactoryProvider storageFactory 属于 utilsModule,我也将其定义为 loginModule 依赖项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    相关资源
    最近更新 更多