找到你要的答案

Q:Variable not defined in Jasmine test case although its in scope

Q:贾斯敏测试用例中未定义的变量,但其范围

I want to test a controller where it listens on an event to do some stuff. The event handler is dependent on a global variable called Main. I'm trying to unit test the event listener by mocking all dependencies but Karma throws error :

ReferenceError: Main is not defined

Angular Code :

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

Spec file :

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'
        }

    });
};

What is the problem? Thanks for help.

我想测试一个控制器,它在某个事件上监听做一些事情。事件处理程序依赖于一个名为main的全局变量。我试图通过嘲笑所有依赖项来测试事件侦听器,但业力抛出错误:

referenceerror:主要是没有定义的

角编码:

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'
        }

    });
};

问题是什么?谢谢帮助。

answer1: 回答1:

It's a variable visibility issue because of the scope in which these variables are defined.

For your $viewContentLoaded handler to work properly it needs a Main object which is NOT defined in the current scope or in any of it's parent scopes in the scope chain. The Main mock object that you created using createSpyObj is in the scope of your App test suite defined using describe(). If you look at your code,

describe("App", function () {
    var scope, AppController, Main; 
    /* remaining code */
}

As you can see above, Main is a local variable defined in the describe() method, so it's available only within that function or to any child functions defined inside this function.

Any function outside of describe() like your event handler ($on) in Main JS will not know of its existence. That is the reason you get an error when that handler is invoked.

You can resolve this by initializing Main properly in 2 ways.

  1. You can do this before your event handler is registered either before creating your Angular Module (or) inside the controller.
  2. You can make Main an Angular service in the same module, inject it into your controller like below.

Main JS

 App.service('Main', function(){

 });

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

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

你viewcontentloaded美元处理器正常工作需要的主要对象不在当前的范围或任何它的父作用域链中定义的范围。主要模拟对象创建使用createspyobj在范围定义你的应用程序的测试套件使用describe()。如果你看你的代码,

describe("App", function () {
    var scope, AppController, Main; 
    /* remaining code */
}

As you can see above, Main is a local variable defined in the describe() method, so it's available only within that function or to any child functions defined inside this function.

喜欢你的describe()事件处理函数外(美元)主要JS会不知道它的存在。这就是当调用该处理程序时会导致错误的原因。

你能解决这2种主要的正确初始化。

  1. You can do this before your event handler is registered either before creating your Angular Module (or) inside the controller.
  2. You can make Main an Angular service in the same module, inject it into your controller like below.

主要的JS

 App.service('Main', function(){

 });

 App.controller('AppController', ['$scope', 'Main', function($scope, Main){
        $scope.$on('$viewContentLoaded', function() {
            Main.initComponents(); // init core components
        });
 }]);
javascript  angularjs  unit-testing  scope  jasmine