0

我正在尝试使用 Karma、Jasmine 和 ngMock 学习 Angular 的单元测试。Angular 文档中至少有两个地方展示了如何为控制器编写单元测试,我只是对他们如何做事有几个问题。

控制器文档中,关于测试控制器的部分

describe('myController function', function() {

  describe('myController', function() {
    var $scope;

    beforeEach(module('myApp'));

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

    it("...");
  });
});

问题 1:这对我来说很有意义,但我不太明白。我知道这$controller是抓取“MyController”的一个实例,但看起来返回的内容没有被保存或在任何地方使用,所以我唯一能想到的是我们抓取该控制器以获得正确的$scope对象?即使这样,它似乎也没有被保存在任何地方的变量中,所以我仍然对它在幕后的工作方式有点困惑。我对如何module()工作也有同样的困惑,因为我们似乎在声明我们正在使用哪个模块,但没有在其他任何地方保存或使用它。幕后是否有缓存模块/控制器/范围的东西,所以我们不必手动保存它或其他东西?


这是单元测试文档中的另一个示例:

describe('PasswordController', function() {
  beforeEach(module('app'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

  describe('$scope.grade', function() {
    it('sets the strength to "strong" if the password length is >8 chars', function() {
      var $scope = {};
      var controller = $controller('PasswordController', { $scope: $scope });
      $scope.password = 'longerthaneightchars';
      $scope.grade();
      expect($scope.strength).toEqual('strong');
    });
  });
});

问题 2:beforeEach函数中,它正在做下划线包装的事情。这是否只是为了让您可以在整个过程中保持相同的服务名称而无需更改它?

问题 3:it()然后$controller用来做它的事情,这一次保存返回的东西, var controller 但似乎仍然从未使用过它。那么为什么要将它保存到变量中呢?我唯一能想到的就是你保存它以防你需要在这个it()块内再次使用它,但他们只是在这个例子中没有?


我一直在寻找一个好的解释,但我似乎找不到。抱歉,如果我错过了一个愚蠢的解释,但我时间紧迫,不能再花时间旋转我的轮子了。

4

2 回答 2

1

1) 调用 module('myApp') 将加载您的模块,本质上运行所有模式函数(提供程序、指令、控制器)的声明,使它们可供您以后使用。这就是 Angular 在调用 $controller('myController') 时如何找到我的 Controller。

至于从 $controller 返回的控制器的引用,这取决于您的实现。如果您使用 $scope,一旦控制器被实例化,您就可以通过 $scope 引用这些函数。

在控制器中……</p>

$scope.cancel = function () {
   doStuff();
};

然后你的测试可能看起来像这样......

describe(’test Controller', function () {
  var scope;

  beforeEach(module(‘myApp'));

  beforeEach(inject(function ($rootScope, $controller) {
    scope = $rootScope.$new();
    $controller(‘myController', {
      $scope: scope
    });
  }));

  describe(’testing stuff', function () {
    it(’test cancel function', function () {
      scope.cancel();
      expect(...);
    });
  });
});

如果您使用 controllerAs 语法并将函数分配给控制器中的“this”,则可以在测试中使用对控制器的引用……</p>

在控制器中……</p>

this.cancel = function () {
   doStuff();
};

然后你的测试可能看起来像这样......

describe(’test Controller', function () {
  var scope,
      controller;

  beforeEach(module(‘myApp'));

  beforeEach(inject(function ($rootScope, $controller) {
    scope = $rootScope.$new();
    controller = $controller(‘myController', {
      $scope: scope
    });
  }));

  describe(’testing stuff', function () {
    it(’test cancel function', function () {
      controller.cancel();
      expect(...);
    });
  });
});

2) 是的,$controller是避免名称冲突的便利;

3)我认为这是一个不好的例子,如果他们不使用它,他们不应该需要保存它。我更喜欢在 beforeEach() 中进行所有测试设置。

于 2015-12-31T18:54:39.457 回答
0

@bobbyz:$controller 服务的第二个参数是注射剂的哈希值。当您为 $scope 添加引用时,根据 Controller 的定义创建控制器实例时,将修改相同的引用对象。这样,$scope 就能够获取所有的方法或变量。

于 2016-10-13T04:46:44.407 回答