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
其中,
- npm 是 Node 包管理器(node package manager)的命令行实用程序,用于在任何计算机上安装自定义模块。
- install 参数指示 npm 命令行实用程序需要进行安装。
- 命令行中指定了与 Karma 配合工作所需的 3 个库。
- karma 是将用于测试目的的核心库。
- karma-chrome-launcher 是一个单独的库,它使 Chrome 浏览器能够识别 karma 命令。
- karma-jasmine – 这会安装 jasmine,它是 Karma 的一个依赖框架。
第二步)下一步是安装 karma 命令行实用程序。这对于执行 karma 行命令是必需的。karma 行实用程序将用于初始化测试的 karma 环境。
要安装命令行实用程序,请从命令行执行以下行
npm install karma-cli
其中,
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 运行时引擎以下信息
- ‘Your application Name’ – 这将替换为您应用程序的名称。
- ‘Your application Name’/AngularJS/AngularJS.js’ – 这告诉 karma 您的应用程序依赖于 AngularJS 的核心模块。
- ‘Your application Name’/AngularJS-mocks/AngularJS-mocks.js’ – 这告诉 karma 使用 Angular.JS-mocks.js 文件中的 AngularJS 单元测试功能。
- 所有主要的应用程序或业务逻辑文件都位于您应用程序的 lib 文件夹中。
- tests 文件夹将包含所有单元测试。
为了检查 karma 是否正常工作,请创建一个名为 Sample.js 的文件,粘贴以下代码,然后将其放入 test 目录中。
describe('Sample test', function() { it('Condition is true', function() { expect('AngularJS').toBe('AngularJS'); }); });
以上代码具有以下几个方面
- describe 函数用于描述测试。在我们的例子中,我们给测试的描述是“Sample test”。
- ‘it’ 函数用于给测试命名。在我们的例子中,我们将测试命名为“Condition is true”。测试的名称需要有意义。
- ‘expect’ 和 ‘toBe’ 关键字的组合说明了测试结果的预期值和实际值。如果实际值和预期值相同,则测试将通过,否则将失败。
当您在命令提示符下执行以下行时,它将执行上述测试文件
KARMA start
下面的输出是从 IDE Webstorm 获得的,其中执行了上述步骤。
- 输出显示在 Webstorm 的 Karma 浏览器中。此窗口显示了 karma 框架中定义的所有测试的执行情况。
- 在这里您可以看到执行的测试的描述,即“Sample test”。
- 接下来,您可以看到名为“Condition is true”的测试本身得到了执行。
- 请注意,由于所有测试旁边都有绿色的“Ok”图标,这表示所有测试都已通过。
测试 AngularJS 控制器
karma 测试框架还具有测试控制器端到端的功能。这包括对控制器中使用的 $scope 对象的测试。
让我们看一个如何实现这一目标的例子。
在我们的示例中,
我们首先需要定义一个控制器。该控制器将执行以下步骤
- 创建一个 ID 变量并将其值设置为 5。
- 将 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 文件夹中。
以下代码仅执行以下操作
- 创建一个名为 sampleApp 的AngularJS 模块
- 创建一个名为 AngularJSController 的控制器
- 创建一个名为 ID 的变量,给它赋值 5,并将其分配给 $scope 对象。
var sampleApp = AngularJS.module('sampleApp',[]); sampleApp.controller('AngularJSController', function($scope) { $scope.ID =5; });
一旦上述代码成功执行,下一步就是创建一个测试用例,以确保代码已正确编写和执行。
我们的测试代码如下所示。
代码将包含在一个名为 ControllerTest.js 的单独文件中,该文件将放置在 tests 文件夹中。以下代码仅执行以下关键操作
- beforeEach 函数 – 此函数用于在测试运行前加载我们的 AngularJS.JS 模块“sampleApp”。请注意,这是 index.js 文件中的模块名称。
- $controller 对象被创建为我们 index.js 文件中定义的控制器“Angular JSController”的模拟对象。在任何单元测试中,模拟对象代表一个用于测试的虚拟对象。此模拟对象将实际模拟我们控制器的行为。
- beforeEach(inject(function(_$controller_) – 这用于将模拟对象注入我们的测试中,使其行为类似于实际控制器。
- var $scope = {}; 这是为 $scope 对象创建的模拟对象。
- var controller = $controller(‘AngularJSController’, { $scope: $scope }); – 在这里,我们正在检查名为“Angular.JSController”的控制器是否存在。在此,我们将 Index.js 文件中 $scope 对象的所有变量分配给测试文件中的 $scope 对象。
- 最后,我们将 $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。
让我们看一个如何实现这一目标的例子。
在我们的示例中,我们将首先定义一个自定义指令,该指令执行以下操作
- 创建一个名为 sampleApp 的 AngularJS 模块
- 创建一个名为 Guru99 的自定义指令
- 创建一个返回模板的函数,该模板包含一个标题标签,显示文本“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 文件夹中。以下代码仅执行以下关键操作
- beforeEach 函数 – 此函数用于在测试运行前加载我们的 Angular JS 模块“sampleApp”。
- $compile 服务用于编译指令。此服务是强制性的,需要声明,以便 Angular.JS 可以使用它来编译我们的自定义指令。
- $rootscope 是任何 AngularJS 应用程序的主要范围。我们在前面的章节中已经看到过控制器的 $scope 对象。嗯,$scope 对象是 $rootscope 对象的子对象。在此声明它的原因是,我们通过自定义指令对实际的 HTML 标签进行了更改。因此,我们需要使用 $rootscope 服务,它实际上会监听或知道 HTML 文档内的任何更改。
- var element = $compile(“<ng-Guru99></ng-Guru99>”) – 这用于检查我们的指令是否如预期那样被注入。我们的自定义指令名称是 Guru99,并且从我们的自定义指令章节中我们知道,当指令被注入到我们的 HTML 中时,它将被注入为‘<ng-Guru99></ng-Guru99>’。因此,此语句用于进行此检查。
- 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 指令创建一个数据表。
- 我们首先创建一个名为“tutorial”的变量,并在一个步骤中为其分配一些键值对。每个键值对将用作显示表格的数据。然后将 tutorial 变量分配给 scope 对象,以便在视图中访问它。
- 对于表格中的每一行数据,我们都使用了 ng-repeat 指令。该指令通过使用变量 ptutor 来遍历 tutorial scope 对象中的每个键值对。
- 最后,我们使用 <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 文件夹中。以下代码仅执行以下关键操作
- browser 函数由 protractor 库提供,并假定我们的 AngularJS 应用程序(具有上面显示的 C代码)正在我们的站点 URL – https://:8080/Guru99/ 上运行。
- var list=element.all(by.repeater(ptutor in tutorial’)); -此代码行实际上正在获取由代码‘ptutor in tutorial’填充的 ng-repeat 指令。element 和 by.repeater 是 protractor 库提供的特殊关键字,允许我们获取 ng-repeat 指令的详细信息。
- 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 页面上所有元素的特殊方法。