【问题标题】:Angular Unit Testing on Controller using a Service - Breaking on Inject使用服务对控制器进行 Angular 单元测试 - 注入中断
【发布时间】:2013-07-27 22:37:03
【问题描述】:

我正在为 karma 编写单元测试,但无法运行。它似乎正在破坏注入功能。我认为这与我如何在测试中获得控制器有关,但找不到解决方案。

我最近几天才开始使用 Angular,所以任何建议都将不胜感激,谢谢!

错误:

Error: Argument 'fn' is not a function, got string
  at Error (<anonymous>)
  at $a (path/app/lib/angular.js:16:453)
  at qa (path/app/lib/angular.js:17:56)
  at Cb (path/app/lib/angular.js:24:458)
  at Object.d [as invoke] (path/app/lib/angular.js:27:66)
  at path/app/lib/angular.js:26:194
  at Array.forEach (native)
  at m (path/app/lib/angular.js:6:192)
  at e (path/app/lib/angular.js:25:298)
  at Object.sb [as injector] (path/app/lib/angular.js:29:360)
TypeError: Cannot read property 'zip' of undefined
  at null.<anonymous> (path/test/unit/controllersSpec.js:26:19)

测试:

'use strict';

/* jasmine specs for controllers go here */

describe('influences controllers', function() {
  beforeEach(module('influences.controllers', ['ui.bootstrap', 'influences.services']));

  describe('IndividualCtrl', function(){

    var scope, ctrl, service, $httpBackend;

    beforeEach(inject(function(_$httpBackend_, $rootScope, $controller, Api_sunlight_get) {
      console.log('*** IN INJECT!!***: ', Api_sunlight_get);
      $httpBackend = _$httpBackend_;
      // ignore for now... this is an example of how I might implement this later
      // $httpBackend.expectGET('data/products.json').
      //     respond([{name: 'Celeri'}, {name: 'Panais'}]);

      scope = $rootScope.$new();
      service = Api_sunlight_get;
      ctrl = $controller('IndividualCtrl', {$scope: scope, Api_sunlight_get: service
      });
    }));

    it('should create "products" model with 2 products fetched from xhr', function() {
      console.log('*** IN TEST!!***: ', scope);
      expect(scope.zip).toEqual(12345);
    });
  });
});

控制器:

angular
  .module('influences.controllers', ['ui.bootstrap', 'influences.services'])
  .controller('IndividualCtrl', ['$scope', 'Api_sunlight_get', ($scope, Api_sunlight_get)->
    # set default variables
    $scope.zip = $scope.zip or 94102  # set default zip if one is not chosen

    # Define Methods
    $scope.get_rep_data_by_zip = ()->
      $scope.reps =  Api_sunlight_get "legislators/locate?zip=#{$scope.zip}" $scope.update_rep_data_by_zip

    $scope.update_rep_data_by_zip = ()->
      $scope.selected_rep = $scope.reps  # sets default selection for reps buttons
      for rep in $scope.reps
        rep.fullname = "" + rep.title + " " + rep.first_name + " " + rep.last_name

    # watchers
    $scope.$watch('zip', $scope.get_rep_data_by_zip)

    # initial run
    $scope.get_rep_data_by_zip()

服务:

angular
  .module('influences.services', [])
  .factory 'Api_sunlight_get', ['$http', ($http)->
    return (path, callback)->
      $http
        url: "http://congress.api.sunlightfoundation.com/#{path}&apikey=xxxx"
        method: "GET"
      .success (data, status, headers, config)->
        callback data.results
      .error (data, status, headers, config)->
        console.log("Error pulling #{path} from Sunlight API!")
  ]

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    我认为这是模块influences.controllers的依赖没有被加载的问题。我尝试了您的程序的一个相当缩小的版本,并得到了与您完全相同的错误。只有在这里咨询this question 之后,我才设法得到它。请阅读作者的答案,我认为这会很有帮助。

    无论如何,这可能是您在 Test 文件中加载 actual ui.bootstrapinfluences.services 模块的方法:

    'use strict';
    
    /* jasmine specs for controllers go here */
    
    describe('influences controllers', function() {
      // Change is here. Notice how the dependencies of the influences.controllers
      // module are specified separately in another beforeEach directive
      beforeEach(module('influences.controllers'));
      beforeEach(function() {
        module('ui.bootstrap');
        module('influences.services');
      });
    
      describe('IndividualCtrl', function(){
    
        var scope, ctrl, service, $httpBackend;
    
        beforeEach(inject(function(_$httpBackend_, $rootScope, $controller, Api_sunlight_get) {
          console.log('*** IN INJECT!!***: ', Api_sunlight_get);
          $httpBackend = _$httpBackend_;
          // ignore for now... this is an example of how I might implement this later
          // $httpBackend.expectGET('data/products.json').
          //     respond([{name: 'Celeri'}, {name: 'Panais'}]);
    
          scope = $rootScope.$new();
          service = Api_sunlight_get;
          ctrl = $controller('IndividualCtrl', {$scope: scope, Api_sunlight_get: service
          });
        }));
    
        it('should create "products" model with 2 products fetched from xhr', function() {
          console.log('*** IN TEST!!***: ', scope);
          expect(scope.zip).toEqual(12345);
        });
      });
    });
    

    如果您想模拟这两个依赖项,您可能需要参考上面的链接,为方便起见,我将在此重复:Mocking Angular module dependencies in Jasmine unit tests

    如果您有兴趣,以下是我尝试过的缩小版本的所有文件。只需将它们放在同一个文件夹中即可。您将需要 karmaangular.jsphantomjsangular-mocks 来运行测试。 angular-mocks 可以从 angular-seed 项目here获得。

    要运行测试,只需:

    karma start karma.test.conf.js
    

    很抱歉将所有文件放在这里,因为我真的不知道这样放置多个文件的好地方。

    ctrl.js

    angular.module('influences.controllers', ['influences.services'])
        .controller('IndividualCtrl', [
            '$scope', 
            'Api_sunlight_get',
            function($scope, Api_sunlight_get) {
                $scope.zip = $scope.zip || 12345;
            }
        ])
    

    service.js

    angular.module('influences.services', [])
        .factory('Api_sunlight_get', [
            '$http',
            function($http) {
                console.log('Api_sunlight_get factory called');
            }
        ])
    

    test.spec.js

    describe('influences controllers', function() {
        beforeEach(module('influences.controllers'));
        beforeEach(function() {
            module('influences.services');
        });
        describe('IndividualCtrl', function() {
            var scope
              , ctrl
              , service
              , $httpBackend;
            beforeEach(inject(function(_$httpBackend_, $rootScope, $controller, Api_sunlight_get) {
                console.log('*** IN INJECT!! ***');
                $httpBackend = _$httpBackend_;
                scope = $rootScope.$new();
                service = Api_sunlight_get;
                ctrl = $controller('IndividualCtrl', {
                    $scope: scope,
                    Api_sunlight_get: service
                });
            }));
    
            it('should set the correct zip value', function() {
                expect(scope.zip).toBe(12345);
            });
        });
    });
    

    karma.test.conf.js

    // Karma configuration
    // Generated on Tue Jul 02 2013 11:23:33 GMT+0800 (SGT)
    
    
    // base path, that will be used to resolve files and exclude
    basePath = './';
    
    
    // list of files / patterns to load in the browser
    files = [
      JASMINE,
      JASMINE_ADAPTER,
      'angular.min.js',
      'angular-mocks.js',
      'service.js',
      'ctrl.js',
      'test.spec.js'
    ];
    
    
    // list of files to exclude
    exclude = [
    ];
    
    
    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit'
    reporters = ['progress'];
    
    hostname = '127.0.0.1';
    
    // web server port
    port = 9876;
    
    
    // cli runner port
    runnerPort = 9100;
    
    
    // enable / disable colors in the output (reporters and logs)
    colors = true;
    
    
    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel = LOG_INFO;
    
    
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch = true;
    
    
    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers = ['PhantomJS'];
    
    
    // If browser does not capture in given timeout [ms], kill it
    captureTimeout = 60000;
    
    
    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun = true;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-27
      • 2012-05-20
      • 2016-02-20
      • 1970-01-01
      • 2016-12-21
      • 1970-01-01
      • 2015-09-20
      • 2023-03-12
      相关资源
      最近更新 更多