Javascript Jasmine测试用例中未定义变量,尽管它在范围内

Javascript Jasmine测试用例中未定义变量,尽管它在范围内,javascript,angularjs,unit-testing,scope,jasmine,Javascript,Angularjs,Unit Testing,Scope,Jasmine,我想测试一个控制器,它监听一个事件来做一些事情。事件处理程序依赖于名为Main的global变量。我试图通过模拟所有依赖项对事件侦听器进行单元测试,但Karma会抛出错误: ReferenceError:Main未定义 角度代码: App.controller('AppController', ['$scope', function($scope){ $scope.$on('$viewContentLoaded', function() { Main.initCompon

我想测试一个控制器,它监听一个事件来做一些事情。事件处理程序依赖于名为
Main
global变量。我试图通过模拟所有依赖项对事件侦听器进行单元测试,但Karma会抛出错误:

ReferenceError:Main未定义

角度代码:

App.controller('AppController', ['$scope', function($scope){
    $scope.$on('$viewContentLoaded', function() {
        Main.initComponents(); // init core components
    });
}]);
describe("App", function () {
    var scope, AppController, Main;
    describe("Login", function () {
        beforeEach(module("App"));
        beforeEach(inject(['$rootScope', '$controller', function($rootScope, $controller){
            scope = $rootScope.$new();
            Main = jasmine.createSpyObj("Main",["initComponents"]);
            AppController = $controller('AppController', {$scope : scope});
        }]));
        it("should call initComponents() on Main module on $viewContentLoaded event", inject(['$rootScope', function ($rootScope) {
            $rootScope.$broadcast('$viewContentLoaded');
            expect(Main.initComponents).toHaveBeenCalled();
        }]));
    });
});
规范文件:

App.controller('AppController', ['$scope', function($scope){
    $scope.$on('$viewContentLoaded', function() {
        Main.initComponents(); // init core components
    });
}]);
describe("App", function () {
    var scope, AppController, Main;
    describe("Login", function () {
        beforeEach(module("App"));
        beforeEach(inject(['$rootScope', '$controller', function($rootScope, $controller){
            scope = $rootScope.$new();
            Main = jasmine.createSpyObj("Main",["initComponents"]);
            AppController = $controller('AppController', {$scope : scope});
        }]));
        it("should call initComponents() on Main module on $viewContentLoaded event", inject(['$rootScope', function ($rootScope) {
            $rootScope.$broadcast('$viewContentLoaded');
            expect(Main.initComponents).toHaveBeenCalled();
        }]));
    });
});
karma.conf.js:

module.exports = function(config){
    config.set({

        basePath : './',

        files : [
            'app/bower_components/angular/angular.js',
            'app/bower_components/oclazyload/dist/oclazyLoad.min.js',
            'app/bower_components/angular-ui-router/release/angular-ui-router.min.js',
            'app/bower_components/angular-mocks/angular-mocks.js',
            'app/**/app.js',
            'app/**/controllers.js',
            'app/**/services.js',
            'app/**/directives.js',
            'app/**/filters.js',
            'app/**/routes.js',
            'app/**/specs.js'
        ],

        autoWatch : true,

        frameworks: ['jasmine'],

        browsers : ['Chrome'],

        plugins : [
            'karma-chrome-launcher',
            'karma-firefox-launcher',
            'karma-jasmine',
            'karma-junit-reporter'
        ],

        junitReporter : {
            outputFile: 'test_out/unit.xml',
            suite: 'unit'
        }

    });
};

有什么问题?感谢您的帮助。

这是一个变量可见性问题,因为定义这些变量的范围

要使
$viewContentLoaded
处理程序正常工作,它需要一个
Main
对象,该对象在当前作用域或作用域链中的任何其父作用域中未定义。使用
createSpyObj
创建的
Main
模拟对象在使用
descripe()
定义的
App
测试套件的范围内。如果你看看你的代码

describe("App", function () {
    var scope, AppController, Main; 
    /* remaining code */
}
如上所示,
Main
是在
descripe()
方法,因此它仅在该函数中可用,或者 在此函数中定义的任何子函数

descripe()
之外的任何函数,比如mainjs中的事件处理程序($on),都不会知道它的存在。这就是调用该处理程序时出现错误的原因

您可以通过以下两种方式正确初始化
Main
来解决此问题

  • 您可以在注册事件处理程序之前执行此操作,或者在控制器内创建角度模块(或)
  • 您可以在同一模块中创建
    Main
    角度服务,将其注入 您的控制器如下所示
  • 主JS

     App.service('Main', function(){
    
     });
    
     App.controller('AppController', ['$scope', 'Main', function($scope, Main){
            $scope.$on('$viewContentLoaded', function() {
                Main.initComponents(); // init core components
            });
     }]);
    

    如错误中所述,在存在角度代码的主JS文件中,应该有一个object类型的
    Main
    变量。只能存根/模拟现有对象。你不能在你的规范中创建一个新的Spy对象,并且期望它在你的主JS中是已知的。@Arkantos,为什么javascript不使用范围内的
    main
    ?在控制器启动之前,定义了主管道。