AngularJS 单元测试:Karma Jasmine 教程

Angular.JS 最出色的功能之一是测试方面。当 Google 的开发人员开发 AngularJS 时,他们考虑到了测试,并确保整个 AngularJS 框架都是可测试的。

在 AngularJS 中,测试通常使用 Karma(框架)进行。虽然可以在没有 Karma 的情况下进行 Angular JS 测试,但 Karma 框架对于测试 AngularJS 代码具有如此出色的功能,以至于使用该框架是有意义的。

  • 在 AngularJS 中,我们可以分别对控制器和指令执行单元测试
  • 我们还可以执行 AngularJS 的端到端测试,也就是从用户角度进行的测试。

Karma 框架的介绍与安装

Karma 是由 Google 的 Angular JS 团队创建的自动化测试工具。使用 Karma 的第一步是安装 Karma。Karma 通过 npm(一个用于在本地计算机上轻松安装模块的包管理器)进行安装。

安装 Karma

通过 npm 安装 Karma 分为两个步骤。

第一步)从命令行执行以下行

npm install karma karma-chrome-launcher karma-jasmine

其中,

  1. npm 是 Node 包管理器(node package manager)的命令行实用程序,用于在任何计算机上安装自定义模块。
  2. install 参数指示 npm 命令行实用程序需要进行安装。
  3. 命令行中指定了与 Karma 配合工作所需的 3 个库。
    • karma 是将用于测试目的的核心库。
    • karma-chrome-launcher 是一个单独的库,它使 Chrome 浏览器能够识别 karma 命令。
    • karma-jasmine – 这会安装 jasmine,它是 Karma 的一个依赖框架。

第二步)下一步是安装 karma 命令行实用程序。这对于执行 karma 行命令是必需的。karma 行实用程序将用于初始化测试的 karma 环境。

要安装命令行实用程序,请从命令行执行以下行

npm install karma-cli

其中,

  • karma-cli 用于安装 karma 的命令行界面,它将用于在命令行界面中编写 karma 命令。
  • Karma 框架的配置

    下一步是配置 karma,可以通过以下命令完成

    "karma –init"

    执行上述步骤后,karma 将创建一个 karma.conf.js 文件。该文件可能看起来像下面所示的代码片段

    files: [
      'Your application Name'/AngularJS/AngularJS.js',
      'Your application Name'/AngularJS-mocks/AngularJS-mocks.js',
      'lib/app.js',
      'tests/*.js'
    ]

    上述配置文件会告知 karma 运行时引擎以下信息

    1. ‘Your application Name’ – 这将替换为您应用程序的名称。
    2. Your application Name’/AngularJS/AngularJS.js’ – 这告诉 karma 您的应用程序依赖于 AngularJS 的核心模块。
    3. ‘Your application Name’/AngularJS-mocks/AngularJS-mocks.js’ – 这告诉 karma 使用 Angular.JS-mocks.js 文件中的 AngularJS 单元测试功能。
    4. 所有主要的应用程序或业务逻辑文件都位于您应用程序的 lib 文件夹中。
    5. tests 文件夹将包含所有单元测试。

    为了检查 karma 是否正常工作,请创建一个名为 Sample.js 的文件,粘贴以下代码,然后将其放入 test 目录中。

    describe('Sample test', function() {
      it('Condition is true', function() {
        expect('AngularJS').toBe('AngularJS');
      });
    });

    以上代码具有以下几个方面

    1. describe 函数用于描述测试。在我们的例子中,我们给测试的描述是“Sample test”。
    2. ‘it’ 函数用于给测试命名。在我们的例子中,我们将测试命名为“Condition is true”。测试的名称需要有意义。
    3. ‘expect’ 和 ‘toBe’ 关键字的组合说明了测试结果的预期值和实际值。如果实际值和预期值相同,则测试将通过,否则将失败。

    当您在命令提示符下执行以下行时,它将执行上述测试文件

    KARMA start

    下面的输出是从 IDE Webstorm 获得的,其中执行了上述步骤。

    Configuration of the Karma Framework

    1. 输出显示在 Webstorm 的 Karma 浏览器中。此窗口显示了 karma 框架中定义的所有测试的执行情况。
    2. 在这里您可以看到执行的测试的描述,即“Sample test”。
    3. 接下来,您可以看到名为“Condition is true”的测试本身得到了执行。
    4. 请注意,由于所有测试旁边都有绿色的“Ok”图标,这表示所有测试都已通过。

    测试 AngularJS 控制器

    karma 测试框架还具有测试控制器端到端的功能。这包括对控制器中使用的 $scope 对象的测试。

    让我们看一个如何实现这一目标的例子。

    在我们的示例中,

    我们首先需要定义一个控制器。该控制器将执行以下步骤

    1. 创建一个 ID 变量并将其值设置为 5。
    2. 将 ID 变量分配给 $scope 对象。

    我们的测试将测试此控制器的存在,并测试 $scope 对象的 ID 变量是否设置为 5。

    首先,我们需要确保满足以下先决条件

    通过 npm 安装 Angular.JS-mocks 库。这可以通过在命令提示符下执行以下行来完成

    npm install Angular JS-mocks

    接下来是修改 karma.conf.js 文件,以确保包含正确的测试文件。以下部分仅显示需要修改的 karma.conf.js 的 files 参数

    files: ['lib/AngularJS.js','lib/AngularJS-mocks.js','lib/index.js','test/*.js']
    • ‘files’ 参数基本上告诉 Karma 运行测试所需的所有文件。
    • AngularJS.js 和 AngularJS-mocks.js 文件是运行 AngularJS 单元测试所必需的。
    • index.js 文件将包含我们的控制器代码。
    • tests 文件夹将包含我们所有的 AngularJS 测试。

    以下是我们的 Angular.JS 代码,它将作为 Index.js 文件存储在应用程序的 tests 文件夹中。

    以下代码仅执行以下操作

    1. 创建一个名为 sampleApp 的AngularJS 模块
    2. 创建一个名为 AngularJSController 的控制器
    3. 创建一个名为 ID 的变量,给它赋值 5,并将其分配给 $scope 对象。
    var sampleApp = AngularJS.module('sampleApp',[]);
    sampleApp.controller('AngularJSController', function($scope) {
        $scope.ID =5;
    });

    一旦上述代码成功执行,下一步就是创建一个测试用例,以确保代码已正确编写和执行。

    我们的测试代码如下所示。

    代码将包含在一个名为 ControllerTest.js 的单独文件中,该文件将放置在 tests 文件夹中。以下代码仅执行以下关键操作

    1. beforeEach 函数 – 此函数用于在测试运行前加载我们的 AngularJS.JS 模块“sampleApp”。请注意,这是 index.js 文件中的模块名称。
    2. $controller 对象被创建为我们 index.js 文件中定义的控制器“Angular JSController”的模拟对象。在任何单元测试中,模拟对象代表一个用于测试的虚拟对象。此模拟对象将实际模拟我们控制器的行为。
    3. beforeEach(inject(function(_$controller_) – 这用于将模拟对象注入我们的测试中,使其行为类似于实际控制器。
    4. var $scope = {}; 这是为 $scope 对象创建的模拟对象。
    5. var controller = $controller(‘AngularJSController’, { $scope: $scope }); – 在这里,我们正在检查名为“Angular.JSController”的控制器是否存在。在此,我们将 Index.js 文件中 $scope 对象的所有变量分配给测试文件中的 $scope 对象。
    6. 最后,我们将 $scope.ID 与 5 进行比较。
    describe('AngularJSController', function() {
        beforeEach(module('sampleApp'));
    
        var $controller;
    
        beforeEach(inject(function(_$controller_){
                  $controller = _$controller_;
        }));
    
        describe('$scope.ID', function() {
            it('Check the scope object', function() {
                var $scope = {};
                var controller = $controller('AngularJSController', { $scope: $scope });
                expect($scope.ID).toEqual(5);
            });
        });
    });

    上述测试将在 karma 浏览器中运行,并给出与上一主题中显示的相同通过结果。

    测试 AngularJS 指令

    karma 测试框架还具有测试自定义指令的功能。这包括自定义指令中使用的 templateUrl。

    让我们看一个如何实现这一目标的例子。

    在我们的示例中,我们将首先定义一个自定义指令,该指令执行以下操作

    1. 创建一个名为 sampleApp 的 AngularJS 模块
    2. 创建一个名为 Guru99 的自定义指令
    3. 创建一个返回模板的函数,该模板包含一个标题标签,显示文本“This is AngularJS Testing。”
    var sampleApp = AngularJS.module('sampleApp',[]);
    sampleApp.directive('Guru99', function () {
        return {
            restrict: 'E',
            replace: true,
            template: '<h1>This is AngularJS Testing</h1>'
        };
    });

    一旦上述代码成功执行,下一步就是创建一个测试用例,以确保代码已正确编写和执行。我们的测试代码如下所示。

    代码将包含在一个名为 DirectiveTest.js 的单独文件中,该文件将放置在 tests 文件夹中。以下代码仅执行以下关键操作

    1. beforeEach 函数 – 此函数用于在测试运行前加载我们的 Angular JS 模块“sampleApp”。
    2. $compile 服务用于编译指令。此服务是强制性的,需要声明,以便 Angular.JS 可以使用它来编译我们的自定义指令。
    3. $rootscope 是任何 AngularJS 应用程序的主要范围。我们在前面的章节中已经看到过控制器的 $scope 对象。嗯,$scope 对象是 $rootscope 对象的子对象。在此声明它的原因是,我们通过自定义指令对实际的 HTML 标签进行了更改。因此,我们需要使用 $rootscope 服务,它实际上会监听或知道 HTML 文档内的任何更改。
    4. var element = $compile(“<ng-Guru99></ng-Guru99>”) – 这用于检查我们的指令是否如预期那样被注入。我们的自定义指令名称是 Guru99,并且从我们的自定义指令章节中我们知道,当指令被注入到我们的 HTML 中时,它将被注入为‘<ng-Guru99></ng-Guru99>’。因此,此语句用于进行此检查。
    5. expect(element.html()).toContain(“This is AngularJS Testing”) – 这用于指示 expect 函数查找该元素(在我们的例子中是 div 标签)是否包含内部 HTML 文本“This is AngularJS Testing”。
    describe('Unit testing directives', function() {
      var $compile,
          $rootScope;
       beforeEach(module('sampleApp'));
    
      beforeEach(inject(function(_$compile_, _$rootScope_){
        $compile = _$compile_;
        $rootScope = _$rootScope_;
     }));
    
     it('Check the directive', function() {
        // Compile a piece of HTML containing the directive
        var element = $compile("<ng-Guru99></ng-Guru99>")($rootScope);
        $rootScope.$digest();
        expect(element.html()).toContain("This is AngularJS Testing");
      });
    });

    上述测试将在 karma 浏览器中运行,并给出与上一主题中显示的相同通过结果。

    AngularJS JS 应用程序的端到端测试

    karma 测试框架与 Protractor 框架一起,具备了端到端测试 Web 应用程序的功能。

    因此,不仅是指令和控制器的测试,还包括 HTML 页面上出现的任何其他内容的测试。

    让我们看一个如何实现这一目标的例子。

    在下面的示例中,我们将有一个 AngularJS 应用程序,它使用 ng-repeat 指令创建一个数据表。

    1. 我们首先创建一个名为“tutorial”的变量,并在一个步骤中为其分配一些键值对。每个键值对将用作显示表格的数据。然后将 tutorial 变量分配给 scope 对象,以便在视图中访问它。
    2. 对于表格中的每一行数据,我们都使用了 ng-repeat 指令。该指令通过使用变量 ptutor 来遍历 tutorial scope 对象中的每个键值对。
    3. 最后,我们使用 <td> 标签以及键值对(ptutor.Name 和 ptutor.Description)来显示表格数据。
    <table >
                 <tr ng-repeat="ptutor in tutorial">
                       <td>{{ ptutor.Name }}</td>
    	               <td>{{ ptutor.Description }}</td>
                 </tr>
       </table>
    </div>
      <script type="text/javascript">
          var app = AngularJS.module('DemoApp', []);
            app.controller('DemoController', function($scope) {
               $scope.tutorial =[
                    {Name: "Controllers" , Description : "Controllers in action"},
                    {Name: "Models" , Description : "Models and binding data"},
    	            {Name: "Directives" , Description : "Flexibility of Directives"}
    			]   });

    一旦上述代码成功执行,下一步就是创建一个测试用例,以确保代码已正确编写和执行。我们的测试代码如下所示。

    我们的测试将实际测试 ng-repeat 指令,并确保它像上面的示例一样包含 3 行数据。

    首先,我们需要确保满足以下先决条件

    通过 npm 安装 protractor 库。这可以通过在命令提示符下执行以下行来完成

    "npm install protractor"

    我们的测试代码如下所示。

    代码将包含在一个名为 CompleteTest.js 的单独文件中,该文件将放置在 tests 文件夹中。以下代码仅执行以下关键操作

    1. browser 函数由 protractor 库提供,并假定我们的 AngularJS 应用程序(具有上面显示的 C代码)正在我们的站点 URL – https://:8080/Guru99/ 上运行。
    2. var list=element.all(by.repeater(ptutor in tutorial’)); -此代码行实际上正在获取由代码‘ptutor in tutorial’填充的 ng-repeat 指令。element 和 by.repeater 是 protractor 库提供的特殊关键字,允许我们获取 ng-repeat 指令的详细信息。
    3. expect(list.count()).toEqual(3); – 最后,我们使用 expect 函数来查看我们确实从 ng-repeat 指令中获得了 3 个填充到我们表中的项目。
    Describe('Unit testing end to end', function() {
      beforeEach(function() {
    browser.get('https://:8080/Guru99/');
    })
       it('Check the ng directive', function() {
          var list=element.all(by.repeater(ptutor in tutorial'));
          expect(list.count()).toEqual(3);  }); });

    上述测试将在 karma 浏览器中运行,并给出与上一主题中显示的相同通过结果。

    摘要

    • AngularJS 中的测试是通过使用 karma 框架实现的,该框架由 Google 自己开发。
    • Karma 框架使用 Node 包管理器进行安装。对于基本测试,需要安装的关键模块是 karma、karma-chrome-launcher、karma-jasmine 和 karma-cli。
    • 测试写在单独的 js 文件中,通常放在应用程序的 tests 文件夹中。这些测试文件的位置必须在一个名为 karma.conf.js 的特殊配置文件中指定。Karma 在执行所有测试时会使用此配置文件。
    • Karma 也可用于测试控制器和自定义指令。
    • 对于端到端的 Web 测试,还需要通过 Node 包管理器安装另一个名为 protractor 的框架。该框架提供了可以用于测试 HTML 页面上所有元素的特殊方法。