AngularJS+;CanvasJS:如何进行单元测试?

AngularJS+;CanvasJS:如何进行单元测试?,angularjs,unit-testing,canvasjs,Angularjs,Unit Testing,Canvasjs,我正试图在使用Yeoman构建的AngularJS应用程序中运行单元测试。 我尝试运行的唯一测试只是检查和数组的长度是否正确,但失败了 因为一些与画布有关的事情 这是日志 LOG: 'CanvasJS Error: Chart Container with id "chartContainer" was not found' PhantomJS 1.9.7 (Windows 7) Controller: MainCtrl should attach a list of inputs to the

我正试图在使用Yeoman构建的AngularJS应用程序中运行单元测试。 我尝试运行的唯一测试只是检查和数组的长度是否正确,但失败了 因为一些与画布有关的事情

这是日志

LOG: 'CanvasJS Error: Chart Container with id "chartContainer" was not found'
PhantomJS 1.9.7 (Windows 7) Controller: MainCtrl should attach a list of inputs to the scope  FAILED
        TypeError: 'undefined' is not an object (evaluating 'this._toolBar.appendChild')
            at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1799
            at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1919
            at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:2093
            at /path/to/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:12551
            at /path/to/Chart/app/scripts/controllers/main.js:101
            at invoke (/path/to/Chart/app/bower_components/angular/angular.js:3869)
            at instantiate (/path/to/Chart/app/bower_components/angular/angular.js:3880)
            at /path/to/Chart/app/bower_components/angular/angular.js:7134
            at /path/to/Chart/test/spec/controllers/main.js:15
            at invoke (/path/to/Chart/app/bower_components/angular/angular.js:3869)
            at workFn (/path/to/Chart/app/bower_components/angular-mocks/angular-mocks.js:2147)
        undefined
        Expected 0 to be 3.
PhantomJS 1.9.7 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.025 secs / 0.021 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
可以在这里找到应用程序

我不确定我是否在AngularJS应用程序中正确实现了这个库,建议将非常感谢

谢谢

-------------------编辑#1--------------------

下面是一些代码,可以更好地理解场景,正如您所看到的CanvasJS 作为全局库使用,而不是作为服务注入,因此问题之一是,如果没有bower回购协议,那么以这种方式使用第三方库是否正确

我认为这条线是问题的根源

...
$scope.chart = new CanvasJS.Chart('chartContainer', {
...
控制器视图包含“chartContainer”id

Karma.conf.js有所有必需的文件,我想

....
    files: [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/bower_components/angular-animate/angular-animate.js',
      'app/bower_components/angular-cookies/angular-cookies.js',
      'app/bower_components/angular-resource/angular-resource.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-sanitize/angular-sanitize.js',
      'app/bower_components/angular-touch/angular-touch.js',

      'app/bower_components/jquery/dist/jquery.js',
      'app/bower_components/angular-ui/build/angular-ui.js',
      'app/bower_components/jquery-ui/jquery-ui.js',
      'app/scripts/vendor/canvasjs-1.5.0-beta/canvasjs.min.js',

      'app/scripts/directives/directive.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],
...
-------------------编辑#2--------------------

这就是我在收到建议后编辑main.js测试的方式

  beforeEach(inject(function ($controller, $rootScope, $compile) {
    var htmlString = '' +
    '<div ng-controller="MainCtrl">' +
    '    <div id="chartContainer">' +
    '</div>'
    ;
    var element = angular.element(htmlString)
    scope = $rootScope.$new();
    $compile(element)(scope);
    scope.$digest();
    MainCtrl = $controller('MainCtrl', {
      $scope: scope
    });
  }));
更新测试控制器时我是否出错

-------------------编辑#3--------------------

在Ivarni的宝贵帮助下,我最终得到了以下解决方案:

在应用程序控制器中

...
$scope.chart = new $window.CanvasJS.Chart('chartContainer', {
...
在控制器测试中

...
beforeEach(inject(function ($controller, $rootScope, $compile, $window) {
    $window.CanvasJS = { Chart: function(){
        this.render = function() {};
    } };
...

CanvasJS现在被模拟,UnitTest可以运行:)

我认为您关于导致错误的原因的假设是正确的。您的控制器未连接到DOM,因此它无法定位id为“chartContainer”的任何对象是合理的

对于单元测试,我将尝试与对指令进行单元测试相同的方法。 这是一种类似于

beforeEach(inject(function($rootScope, $compile) {
    var htmlString = '' +
        '<div ng-controller="MainCtrl">' +
        '    <div id="chartContainer">' +
        '</div>'
        ;
    element = angular.element(htmlString)
    scope = $rootScope.$new();
    $compile(element)(scope);
    scope.$digest();
}));
beforeach(注入(函数($rootScope,$compile){
var htmlString=''+
'' +
'    ' +
''
;
元素=角度元素(htmlString)
scope=$rootScope.$new();
$compile(元素)(范围);
范围。$digest();
}));
这将编译一个附加了控制器的最小DOM片段和一个具有CanvasJS所需id的元素。你可能还得再摆弄一点。我不认为使用CanvasJS作为全局配置有问题,只要您确保它包含在karma配置中


另一种探索途径是查看Angular的e2e测试功能。这里有一些文档。当您测试DOM渲染时,这可能更适合。

您好,我已经添加了整个主控制器、它的测试和Karma的配置。我试图对我的测试控制器进行一些编辑,但可能因为错误几乎相同而遗漏了一些内容。我将更新我的问题以获得更好的代码格式。嗯。。如果在编译和消化HTML片段之前初始化控制器会发生什么?如果仍然失败,那么我认为使用量角器/e2e是一种更可行的方法。量角器和e2e测试已经在队列中,但在进行e2e测试之前,我是否应该对需要它的控制器部分进行单元测试?谢谢你的帮助!我不认为e2e测试应该取代单元测试,但在某些情况下,某些功能不适合单元测试。通过包含CanvasJS,控制器已经没有被完全隔离地测试。我并不是说不可能在jasmine中运行,但我使用$compile的goto方法似乎不起作用。也许还有别的办法。如果控制器中有其他与画布无关的功能,那么提供CanvasJS的全局模拟实现仍然可以让您在单元测试中测试这些部分。确定。不要将CanvasJS构造函数作为全局(
new CanvasJS.Chart()
,顺便说一句,它相当于
new window.CanvasJS.Chart()
),而是使用Angular的
$window
服务包装窗口。现在,您的代码变成了
new$window.CanvasJS.Chart()
。现在,您可以将一个模拟的
$window
传递给您的控制器,就像您已经将
$scope
传递给它一样。
LOG: 'CanvasJS Error: Chart Container with id "chartContainer" was not found'
PhantomJS 1.9.7 (Windows 7) Controller: MainCtrl should attach a list of inputs to the scope  FAILED
        TypeError: 'undefined' is not an object (evaluating 'this._toolBar.appendChild')
            at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1799
            at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:1919
            at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:2093
            at /path/to/workspace/Chart/app/scripts/vendor/canvasjs-1.5.0-beta/source/canvasjs.js:12551
            at /path/to/workspace/Chart/app/scripts/controllers/main.js:101
            at invoke (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3869)
            at instantiate (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3880)
            at /path/to/workspace/Chart/app/bower_components/angular/angular.js:7134
            at /path/to/workspace/Chart/app/bower_components/angular/angular.js:6538
            at forEach (/path/to/workspace/Chart/app/bower_components/angular/angular.js:330)
            at nodeLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:6552)
            at compositeLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:5986)
            at publicLinkFn (/path/to/workspace/Chart/app/bower_components/angular/angular.js:5891)
            at /path/to/workspace/Chart/test/spec/controllers/main.js:20
            at invoke (/path/to/workspace/Chart/app/bower_components/angular/angular.js:3869)
            at workFn (/path/to/workspace/Chart/app/bower_components/angular-mocks/angular-mocks.js:2147)
        undefined
        TypeError: 'undefined' is not an object (evaluating 'scope.inputs.length')
            at /path/to/workspace/Chart/test/spec/controllers/main.js:28
PhantomJS 1.9.7 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.029 secs / 0.028 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
...
$scope.chart = new $window.CanvasJS.Chart('chartContainer', {
...
...
beforeEach(inject(function ($controller, $rootScope, $compile, $window) {
    $window.CanvasJS = { Chart: function(){
        this.render = function() {};
    } };
...
beforeEach(inject(function($rootScope, $compile) {
    var htmlString = '' +
        '<div ng-controller="MainCtrl">' +
        '    <div id="chartContainer">' +
        '</div>'
        ;
    element = angular.element(htmlString)
    scope = $rootScope.$new();
    $compile(element)(scope);
    scope.$digest();
}));