编写 AngularJS 控制器单元测试

编写 AngularJS 控制器单元测试

Flying
2014-12-24 / 0 评论 / 178 阅读 / 正在检测是否收录...

介绍完 Karma(测试运行器)和 Jasmine(测试框架)后,让我们看看怎样为 AngularJS 创建的控制器编写测试。看一个非常简单的控制器,类似于在前面章节看到的:

angular-unit-test.svg

编写单元测试

angular.module('notesApp', [])
  .controller('ListCtrl', [function() {

    var self = this;
    self.items = [
      {id: 1, label: 'First', done: true},
      {id: 2, label: 'Second', done: false}
    ];

    self.getDoneClass = function(item) {
      return {
        finished: item.done,
        unfinished: !item.done
      };
    };
}]);

上述实例是一个非常简单的控制器。它只是给控制器实例分配一个数组(范围内的 HTM L可访问它),然后有一个函数表示逻辑,它返回基于项目的完成状态的实际类。让我们看看对于这种控制器 Jasmine 是怎样来编写测试的:

describe('Controller: ListCtrl', function() {
   
  // Instantiate a new version of my module before each test
  beforeEach(module('notesApp'));
 
  var ctrl;
  // Before each unit test, instantiate a new instance
  // of the controller
  beforeEach(inject(function($controller) {
    ctrl = $controller('ListCtrl');
  }));
 
  it('should have items available on load', function() {
    expect(ctrl.items).toEqual([
      {id: 1, label: 'First', done: true},
      {id: 2, label: 'Second', done: false}
    ]);
  });
 
  it('should have highlight items based on state', function() {
    var item = {id: 1, label: 'First', done: true};
 
    var actualClass = ctrl.getDoneClass(item);
    expect(actualClass.finished).toBeTruthy();
    expect(actualClass.unfinished).toBeFalsy();
 
    item.done = false;
    actualClass = ctrl.getDoneClass(item);
    expect(actualClass.finished).toBeFalsy();
    expect(actualClass.unfinished).toBeTruthy();
  });
 
});

在这个例子中 ListCtrl 控制器有两个特殊的单元测试。让我们逐个看一看每个单元测试的有趣之处。

  • 实例化一个模块

作为描述块的一部分我们为 ListCtrl 做的第一件事变是新建一个 AngularJS 模块 notesApp 实例。这会在每个特定单元测试之前影响刚加载的所有与该模块相关的控制器、服务、命令和过滤器。它的优势在于您在一个单元测试设置修改的状态和不能影响另一个单元测试。每个单元测试本质上变得独立和易控制。和其它函数一样,module 方法是AngularJS库提供的文件angular-mocks的辅助方法之一。

  • 注入服务

我们有一个变量 ctrl ,这将在每一个单元测试的控制器实例。 beforeEach 块之后使用所谓的注入,基本上都是用 Jasmine 在 beforeEachit 块中的函数注入 AngularJ S服务。我们将在后面章节详细讲解 AngularJS 服务。但我们要知道有一个名为 $angularjs 服务,可以使用它来实例化控制器。函数可以通过多个参数注入,每一个都参数都是 AngularJS 后来创建并注入到函数的服务。

  • 创建我们的控制器实例

我们使用 $controller 服务来创建 ListCtrl 控制器实例。仅仅通过传入控制器的名称作为 $controller 服务字符串,并返回一个新控制器实例。然后指定给变量 ctrl,我们将在每个独立的测试中使用它。

  • 为构造函数编写一个测试

无论我们在$controller函数定义什么都会在控制器实例化时执行。我们能为$controller函数做的仅有事情就是设置item数组和函数。所以第一个it块测试条目数组的状态,检查实例化及其值是否正确。它使用了Jasmine toEqual匹配器来检查条目数组是否与我们期待的完全相同。

  • 为getDoneClass函数编写测试

我们最后编写测试检查为控制器实例定义的 getDoneClass 函数。通过实例化一些本地测试状态(item对象),再传递给控制器
getDoneClass 函数并存储它的返回值。接下来,我们检查完成与未完成两种状态的真假值。然后我们改变项目的状态,将完成改成未完成 (设置为 false ),然后检查函数是否改变相应的返回值。

上个例子的执行顺序如下:

  1. 执行加载 AngularJS 模块的 beforeEach 块。
  2. 执行创建控制器的 beforeEach 块。
  3. 执行“加载项” it 代码块。
  4. 执行加载 AngularJS 模块的 beforeEach 块。
  5. 执行创建控制器的 beforeEach 块。
  6. 执行 getDoneClass it 块。

因此每个单元测试执行时得到一个干净的状态,并确保一个单元测试的修改和状态更改不影响另一个单元测试。

运行单元测试

我们应该如何运行这些单元测试呢?最简单的方法是从命令行/终端/主机执行以下命令 :

karma start

Karma 开始从执行命令的目录自动查找 karma.conf 的命令。并从该文件获取配置。如果您的配置文件不是命名为karma.conf.js,或者如果它在一个不同的文件夹中,您可以将它作为命令的参数。如下命令:

karma start my.conf.js

在我们的例子中这不是必需的。

这两个命令都会读取配置文件,占用正在测试的文件,启动指定的端口的服务器,然后尝试打开在配置中列出的浏览器(为他们提供安装启动器插件)。

Karma 命令启动用于服务测试文件的测试服务器。打开连接到服务器的每个浏览器顶部会显示一个绿色栏,表明它已经准备好运行测试。如果配置中没有选择任何浏览器,或自动捕获浏览器遇到一些问题,您仍然可以通过在浏览器中打开指定的URL手动地捕获任何浏览器(在任何机器上)。

从控制台/命令窗口执行 karma start 命令,打印测试结果。用来捕获的浏览器本身不打印结果,这是因为浏览器可能在一个完全不同的机器上执行测试。运行成功后在控制台/命令窗口应该打印如下截图:

打印测试结果

如果您已经在您的配置将autoWatch设置为 true,Karma 会在所有的浏览器中自动触发一个测试运行,您可以每次捕捉到测试文件的任何变化。如果没有将 autoWatch 设置为 true,您也可以手动在控制台/终端执行以下命令来触发一个测试运行:

karma run

该命令告诉 Karma 基于配置为当前活跃的服务器再次执行测试。

3

评论 (0)

取消