angularjs - 单元测试中的bindToController

标签 angularjs unit-testing

我在指令中使用bindToController,将隔离范围直接附加到 Controller ,如下所示:

app.directive('xx', function () {
  return {
    bindToController: true,
    controller: 'xxCtrl',
    scope: {
      label: '@',
    },
  };
});

然后在 Controller 中我有一个默认值,以防 HTML 中未指定标签:

app.controller('xxCtrl', function () {
  var ctrl = this;

  ctrl.label = ctrl.label || 'default value';
});

如何在 Jasmine 单元测试中实例化 xxCtrl 以便测试 ctrl.label?

describe('buttons.RemoveButtonCtrl', function () {
  var ctrl;

  beforeEach(inject(function ($controller) {
    // What do I do here to set ctrl.label BEFORE the controller runs?
    ctrl = $controller('xxCtrl');
  }));

  it('should have a label', function () {
    expect(ctrl.label).toBe('foo');
  });
});

检查this测试问题

最佳答案

在 Angular 1.3 中(1.4+ 版本见下文)

深入研究 AngularJS 源代码,我发现 $controller 服务有一个未记录的第三个参数,名为 later(请参阅 $controller source )。

如果为 true,$controller() 返回一个带有属性 instance 的函数,您可以在该属性上设置属性。
当您准备好实例化 Controller 时,调用该函数,它将使用构造函数中可用的属性实例化 Controller 。

您的示例将像这样工作:

describe('buttons.RemoveButtonCtrl', function () {

  var ctrlFn, ctrl, $scope;

  beforeEach(inject(function ($rootScope, $controller) {
    scope = $rootScope.$new();

    ctrlFn = $controller('xxCtrl', {
      $scope: scope,
    }, true);
  }));

  it('should have a label', function () {
    ctrlFn.instance.label = 'foo'; // set the value

    // create controller instance
    ctrl = ctrlFn();

    // test
    expect(ctrl.label).toBe('foo');
  });

});

这是一个更新的 Plunker(必须升级 Angular 才能工作,现在是 1.3.0-rc.4):http://plnkr.co/edit/tnLIyzZHKqPO6Tekd804?p=preview

请注意,可能不建议使用它,引用 Angular 源代码:

Instantiate controller later: This machinery is used to create an instance of the object before calling the controller's constructor itself.

This allows properties to be added to the controller before the constructor is invoked. Primarily, this is used for isolate scope bindings in $compile.

This feature is not intended for use by applications, and is thus not documented publicly.

然而,由于缺乏使用 bindToController: true 测试 Controller 的机制,所以我还是使用了它。也许 Angular 的人应该考虑公开该标志。

它在底层使用了一个临时构造函数,我想我们也可以自己编写它。
您的解决方案的优点是构造函数不会被调用两次,如果属性没有像您的示例中那样具有默认值,这可能会导致问题。

Angular 1.4+(更新2015-12-06):
Angular 团队在 version 1.4.0 中添加了对此的直接支持。 (参见#9425)
您可以将一个对象传递给 $controller 函数:

describe('buttons.RemoveButtonCtrl', function () {

  var ctrl, $scope;

  beforeEach(inject(function ($rootScope, $controller) {
    scope = $rootScope.$new();

    ctrl = $controller('xxCtrl', {
      $scope: scope,
    }, {
      label: 'foo'
    });
  }));

  it('should have a label', function () {
    expect(ctrl.label).toBe('foo');
  });
});

另请参阅 blog post .

关于angularjs - 单元测试中的bindToController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25837774/

相关文章:

unit-testing - F# UnitTest 项目中的 AutoFixture 未在测试资源管理器中显示单元测试

javascript - 在私有(private)方法上使用 Jasmine spyon

c# - 如何在 Unity Test Runner 中测试 Unity 协程

javascript - AngularJS,Ng-repeat 更改/更改 Json 数组的顺序

javascript - 使用带有 ng-repeat 的表内的 Angular js 动态更改 rowspan 值

python - 自定义 django-admin 命令模块的 handle 方法内的单元测试功能

java - 使用 Mockito 对 Map 对象进行单元测试、 spy 和反射

javascript - 在angularJS中添加多个工厂

javascript - 如何在指令中进行递归?

javascript - 在 angular.js 的一项服务中重用方法