AngularJS、RequireJS和因果报应问题

AngularJS、RequireJS和因果报应问题,angularjs,requirejs,jasmine,karma-runner,Angularjs,Requirejs,Jasmine,Karma Runner,为这篇冗长的文章提前道歉。在过去的几天里,我一直被这个问题困扰着。基本上,我有一个带有RequireJS设置的AngularJS项目,运行良好。我试图使用Angular、Require、Karma(Jasmine)组合编写单元测试。我得到的错误是: Error: [ng:areq] Argument 'fn' is not a function, got Object http://errors.angularjs.org/1.2.9/ng/areq?p0=fn&p1=not%20a%2

为这篇冗长的文章提前道歉。在过去的几天里,我一直被这个问题困扰着。基本上,我有一个带有RequireJS设置的AngularJS项目,运行良好。我试图使用Angular、Require、Karma(Jasmine)组合编写单元测试。我得到的错误是:

Error: [ng:areq] Argument 'fn' is not a function, got Object
http://errors.angularjs.org/1.2.9/ng/areq?p0=fn&p1=not%20a%20function%2C%20got%20Object
at D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:78:12
at assertArg (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:1363:11)
at assertArgFn (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:1373:3)
at annotate (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:3019:5)
at invoke (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:3687:21)
at Object.instantiate (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:3721:23)
at D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:6772:28
at null.<anonymous> (D:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:11:24)
at Object.invoke (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:3710:17)
at workFn (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular-mocks.js:2149:20)
Error: Declaration Location
at window.inject.angular.mock.inject (D:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular-mocks.js:2134:2

at null.<anonymous> (D:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:9:20)
at D:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:4:5
....
以下是文件的相关部分:

SimpleControl.js:

define(["app"], function( app ) {

return angular.module("simpleApp").controller("SimpleController", ["$scope",
    function($scope) {
       $scope.msg = "Hello ";
    }
]);
});
karma.conf.js

....
  // list of files / patterns to load in the browser
files: [

  {pattern: 'app/lib/**/*.js', included: false},
  {pattern: 'app/js/controllers/*.js', included: false},
  {pattern: 'app/js/**/*.js', included: false},
  {pattern: 'app/js/services/*.js', included: false},
  {pattern: 'test/spec/*Spec.js', included: false},
  {pattern: 'test/spec/mockApp.js', included: false},
  'test-main.js',
],


// list of files to exclude
exclude: [
  'app/js/main.js', 'app/js/app.js'    ],
....
test-main.js

var tests = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (/Spec\.js$/.test(file)) {
  tests.push(file);
}
}
}

require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/app/js',

paths: {
    "angular" : "../lib/angular/angular",
    "angular-resource" : "../lib/angular/angular-resource",
    "angular-route" : "../lib/angular/angular-route",
    "angular-storage" : "../lib/angular-local-storage",
    "bootstrap-tooltip" : "../lib/bootstrap-tooltip",
    "bootstrap-popover" : "../lib/bootstrap-popover",
    "bootstrap" : "../lib/bootstrap.min",
    "ui-bootstrap-tpls" : "../lib/ui-bootstrap-tpls-0.11.0",
    "dirPagination" : "../lib/dirPagination",
    "translate" : "../lib/angular-translate.min",
    "translationsEN" : "../js/locale/en/translations_en",
    "translationsDE" : "../js/locale/de/translations_de",
    "jQuery" : "../lib/jquery-1.9.0",
    "angular-mocks" : "../lib/angular/angular-mocks",
    "app" : "../../test/spec/mockApp",
    "SimpleController" : "controllers/SimpleController"
},
shim: {

    "jQuery" :{
        exports : 'jQuery'
    },

    "angular" : {
        deps: ["jQuery"],
        exports: 'angular'
    },


    "angular-resource": {
            deps: ["angular"],
            exports : 'ngResource'
    },


    "app" : {
         exports : 'app'
    },

    "SimpleController" : {
        deps : ["app"],
        exports : 'SimpleController'
    },


    "angular-mocks" : {

       deps : ["angular"],
       exports : 'angular-mocks'
     },

    "angular-route": {
      deps: ["angular"],
      exports : 'ngRoute'
  },
  "angular-storage": {
      deps: ["angular"],
      exports : 'angular-storage'
  },
  "bootstrap": {
     deps: ["jQuery"],
        exports : 'bootstrap'

   },
  "bootstrap-tooltip": {
     exports : 'bootstrap-tooltip',
     deps : ["jQuery"]
  },
  "bootstrap-popover": {
      exports : 'bootstrap-popover',
      deps : ["jQuery"]
  },

  "ui-bootstrap-tpls": {
    deps : ["jQuery", "angular", "bootstrap", "bootstrap-tooltip", "bootstrap-popover"],
    exports : 'ui-bootstrap-tpls'
  },
  "dirPagination": {
    deps : ["angular"],
      exports : 'dirPagination'
  },
  "translate": {
    deps : ["angular", "translationsEN", "translationsDE"],
      exports : 'translate'
  }

},
// dynamically load all test files
deps: tests,

// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
mockApp.js:

define(["angular"], function(){ 
    var app = angular.module('simpleApp',[]);
    return app;

});
TestAppSetupSpec.js:

define([ 'angular', 'angular-mocks','SimpleController'], function (
     angular, angularMocks, SimpleController
    ) {
describe('App module tests', function () {
    var module, $rootScope, scope, AppCtrl;

    beforeEach(angular.module("simpleApp"));

    beforeEach(inject(function ($rootScope, $controller) {
        scope = $rootScope.$new();
        AppCtrl =  $controller("SimpleController", {
                '$scope': scope
        });

    }));

    it("App Controller should be defined", function(){

        expect(AppCtrl).not.toBe(null);
    });

});
});
我尝试按照建议使用“SampleController”,但现在我得到:

Chrome 37.0.2062 (Windows 7): Executed 2 of 2 (1 FAILED) (0.026 secs / 0.023 secs)
INFO [watcher]: Changed file "d:/workspace/ecart-   oauth/src/main/webapp/test/spec/TestAppSetupSpec.js".
Chrome 37.0.2062 (Windows 7) App module tests App Controller should be defined FAILED
    TypeError: undefined is not a function
    Error: [ng:areq] Argument 'SimpleController' is not a function, got undefined
    http://errors.angularjs.org/1.2.9/ng/areq?  p0=SimpleController&p1=not%20a%20function%2C%20got%20undefined
        at d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:78:12
        at assertArg (d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:1363:11)
        at assertArgFn (d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:1373:3)
        at d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:6769:9
        at null.<anonymous> (d:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:12:26)
        at Object.invoke (d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular.js:3710:17)
        at workFn (d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular-mocks.js:2149:20)
    Error: Declaration Location
        at window.inject.angular.mock.inject (d:/workspace/ecart-oauth/src/main/webapp/app/lib/angular/angular-mocks.js:2134:2
5)
        at null.<anonymous> (d:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:9:20)
        at d:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:4:5
Chrome37.0.2062(Windows7):执行2次(1次失败)(0.026秒/0.023秒)
信息[观察者]:更改了文件“d:/workspace/ecart-oauth/src/main/webapp/test/spec/TestAppSetupSpec.js”。
应定义Chrome 37.0.2062(Windows 7)应用程序模块测试应用程序控制器失败
TypeError:undefined不是函数
错误:[ng:areq]参数“SimpleControl”不是函数,未定义
http://errors.angularjs.org/1.2.9/ng/areq?  p0=SimpleController&p1=not%20a%20函数%2C%20got%20未定义
在d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular.js:78:12
在assertArg(d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular.js:1363:11)
在assertArgFn(d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular.js:1373:3)
在d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular.js:6769:9
在空。(d:/workspace/ecart oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:12:26)
在Object.invoke(d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular.js:3710:17)
工作时fn(d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular mocks.js:2149:20)
错误:声明位置
在window.inject.angular.mock.inject(d:/workspace/ecart oauth/src/main/webapp/app/lib/angular/angular mocks.js:2134:2
5)
在空。(d:/workspace/ecart oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:9:20)
在d:/workspace/ecart oauth/src/main/webapp/test/spec/TestAppSetupSpec.js:4:5
我错过了什么?
非常感谢您的帮助。

您把事情搞混了:

SimpleController.js
(我猜上面的
SampleController.js
是一个输入错误)返回名为
“simpleap”
角度模块(这是一个对象)。在此模块中,有一个名为
“SimpleController”
的控制器。测试脚本中的正确用法是:

AppCtrl =  $controller("SimpleController", { // NOTE THE QUOTES!!!
    '$scope': scope
});

这就是为什么Angular抱怨说在期望函数的位置发现了一个对象。

我终于实现了这一点——但就我个人而言,即使我有一个模糊的想法,我仍然无法理解为什么它能工作。为将来失去的灵魂张贴

我必须像这样编写SimpleControl:

define(["app"], function(app) {

var SimpleController = 
    function($scope) {
        $scope.sayHello = function() {
            return "Hello";
        }
    }


SimpleController.$inject = ['$scope'];


app.controller('SimpleController', SimpleController);

return SimpleController;  //NOTE: not returning app.controller(..) which returns an object.
 });
测试用例现在看起来像:

define([ 'angular', 'angular-mocks', 'controllers/SimpleController'], function (
     angular, angularMocks, SimpleController
    ) {
describe('App module tests -->', function () {
    var  scope, SimpleCtrl;


    beforeEach(
            function(){
             angular.module("simpleApp");
            }

    );

    beforeEach(inject(function($rootScope, $controller){

        scope = $rootScope.$new();

        SimpleCtrl =  $controller(SimpleController, {
             '$scope': scope
         });
    })

    );

    it("App Controller should be defined", function(){

        expect(SimpleCtrl).not.toBe(null);
    });

    it("The controller should have a sayHello method that says Hello", function(){

        expect(scope.sayHello).toMatch('Hello');

    });

});
});

此外,不需要SimpleControl的路径或垫片声明。使用“controllers/SimpleController”在测试类中查找该文件,该文件位于“app/controllers”子文件夹中。

HI Nikos,我尝试了你的建议,但这次遇到了一个新错误。我已经更新了原来的帖子,好像管理员没有注册。你能确定Angular是自举的吗(打印一条消息或什么的)?还有一些文档说:“
injector()
为每个测试创建$injector的新实例”()。是否在第二次测试运行时Angular没有正确初始化?我也有同样的问题-请参阅
XXX
注释。为了解决这个问题,保留并重新使用原来的注射器。你好,尼科斯,我感谢你的回复。然而,我不知道该把信息放在哪里(我知道我听起来很傻,但请容忍我,我是新来的)。另外,如果你能更具体地说明如何保留和重复使用原装喷油器,那就太好了。非常感谢!如果手动引导Angular,则可以保留从
inj=Angular.bootstrap(文档:[“simpleApp]”)返回的值
。如果Angular自动引导,则可以使用
Angular.element(…element with ng app….injector()
获取喷油器。
define([ 'angular', 'angular-mocks', 'controllers/SimpleController'], function (
     angular, angularMocks, SimpleController
    ) {
describe('App module tests -->', function () {
    var  scope, SimpleCtrl;


    beforeEach(
            function(){
             angular.module("simpleApp");
            }

    );

    beforeEach(inject(function($rootScope, $controller){

        scope = $rootScope.$new();

        SimpleCtrl =  $controller(SimpleController, {
             '$scope': scope
         });
    })

    );

    it("App Controller should be defined", function(){

        expect(SimpleCtrl).not.toBe(null);
    });

    it("The controller should have a sayHello method that says Hello", function(){

        expect(scope.sayHello).toMatch('Hello');

    });

});
});