AngularJS 单元测试:Karma Jasmine 教程
Angular.JS 最出色的功能之一是 测试与验证 方面。Google 的开发人员在开发 AngularJS 时,始终将测试放在第一位,并确保整个 AngularJS 框架都是可测试的。
在 AngularJS 中,测试通常使用 Karma(框架)进行。Angular JS 测试可以在没有 Karma 的情况下进行,但 Karma 框架在测试 AngularJS 代码方面具有如此出色的功能,因此使用该框架是有意义的。
- 在 AngularJS 中,我们可以执行 单元测试 分别为控制器和指令。
- 我们还可以对 AngularJS 进行端到端测试,即从用户角度进行测试。
Karma框架介绍与安装
业力是 测试自动化工具 由 Google 的 Angular JS 团队创建。使用 Karma 的第一步是安装 Karma。Karma 通过 npm 安装(npm 是一种包管理器,用于在本地机器上轻松安装模块)。
安装 Karma
通过 npm 安装 Karma 分为两个步骤。
步骤1) 在命令行中执行下面一行
npm install karma karma-chrome-launcher karma-jasmine
其中,
- npm 是节点包管理器的命令行实用程序,用于在任何机器上安装自定义模块。
- install 参数指示 npm 命令行实用程序需要安装。
- 命令行中指定了 3 个与 karma 协同工作所需的库。
- karma 是用于测试目的的核心库。
- karma-chrome-launcher 是一个单独的库,可以使 karma 命令被 chrome 浏览器识别。
- karma-jasmine – 这将安装 jasmine,它是 Karma 的依赖框架。
步骤2) 下一步是安装 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 运行时引擎以下内容
- “您的应用程序名称” – 这将被您的应用程序的名称替换。
- “您的应用程序名称 '/AngularJS/AngularJS.js' – 这告诉 karma,你的应用程序依赖于 AngularJS 中的核心模块
- '你的应用程序名称'/AngularJS-mocks/AngularJS-mocks.js' – 这告诉 karma 使用 Angular.JS-mocks.js 文件中的 AngularJS 单元测试功能。
- 所有主要应用程序或业务逻辑文件都存在于应用程序的 lib 文件夹中。
- 测试文件夹将包含所有单元测试。
要检查 karma 是否正常运行,请创建一个名为 Sample.js 的文件,输入以下代码并将其放在测试目录中。
describe('Sample test', function() { it('Condition is true', function() { expect('AngularJS').toBe('AngularJS'); }); });
上述代码有以下几个方面
- describe 函数用于对测试进行描述。在我们的例子中,我们为测试提供了“示例测试”的描述。
- “it”函数用于为测试命名。在我们的例子中,我们将测试命名为“条件为真”。测试的名称需要有意义。
- 'expect' 和 'toBe' 关键字的组合表明测试结果的预期值和实际值。如果实际值和预期值相同,则测试将通过,否则将失败。
在命令提示符下执行以下行时,它将执行上述测试文件
KARMA start
以下输出取自 IDE Webstorm 其中执行了上述步骤。
- 输出结果在 Karma 浏览器中 Webstorm. 该窗口显示在 karma 框架中定义的所有测试的执行情况。
- 这里您可以看到执行的测试的描述是“示例测试”。
- 接下来,您可以看到名为“条件为真”的测试本身被执行。
- 请注意,所有测试旁边都有绿色的“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: ['lib/AngularJS.js','lib/AngularJS-mocks.js','lib/index.js','test/*.js']
- “文件”参数基本上告诉 Karma 运行测试所需的所有文件。
- 运行 AngularJS 单元测试需要 AngularJS.js 和 AngularJS-mocks.js 文件
- index.js 文件将包含控制器的代码
- 测试文件夹将包含我们所有的 AngularJS 测试
下面是我们的 Angular.JS 代码,它将作为文件 Index.js 存储在我们应用程序的测试文件夹中。
下面的代码只做了以下事情
- 创建 AngularJS 模块 名为sampleApp
- 创建一个名为 AngularJSController 的控制器
- 创建一个名为 ID 的变量,赋予其值 5,并将其分配给 $scope 对象
var sampleApp = AngularJS.module('sampleApp',[]); sampleApp.controller('AngularJSController', function($scope) { $scope.ID =5; });
一旦上述代码成功执行,下一步就是创建一个 测试用例 以确保代码已正确编写和执行。
我们的测试代码如下所示。
代码将放在一个名为 ControllerTest.js 的单独文件中,该文件将放在测试文件夹中。以下代码仅执行以下关键操作
- beforeEach 函数 – 此函数用于在测试运行之前加载名为“sampleApp”的 AngularJS.JS 模块。请注意,这是 index.js 文件中模块的名称。
- $controller 对象是作为控制器“Angular JSController”的模拟对象创建的,该控制器在我们的 index.js 文件中定义。在任何类型的单元测试中,模拟对象代表将实际用于测试的虚拟对象。这个模拟对象实际上将模拟我们的控制器的行为。
- 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”的自定义指令
- 创建一个函数,返回一个带有标题标签的模板,该标签显示文本“这是 AngularJS 测试”。
var sampleApp = AngularJS.module('sampleApp',[]); sampleApp.directive('Guru99', function () { return { restrict: 'E', replace: true, template: '<h1>This is AngularJS Testing</h1>' }; });
一旦上述代码成功执行,下一步就是创建一个测试用例,以确保代码已正确编写和执行。我们的测试代码如下所示
代码将位于名为 DirectiveTest.js 的单独文件中,该文件将放置在测试文件夹中。以下代码仅执行以下关键操作
- beforeEach 函数——此函数用于在测试运行之前加载名为“sampleApp”的 Angular JS 模块。
- $compile 服务用于编译指令。此服务是必需的,需要声明,以便 Angular.JS 可以使用它来编译我们的自定义指令。
- $rootscope 是任何 AngularJS.JS 应用程序的主要范围。我们在前面的章节中已经看到了控制器的 $scope 对象。好吧,$scope 对象是 $rootscope 对象的子对象。在这里声明它的原因是我们通过自定义指令对 DOM 中的实际 HTML 标签进行更改。因此,我们需要使用 $rootscope 服务,该服务实际上会监听或知道 HTML 文档中发生的任何更改。
- var 元素 = $compile(“ ”)——这用于检查我们的指令是否按应有的方式注入。我们的自定义指令的名称是 Guru99,我们从自定义指令章节中知道,当指令注入到我们的 HTML 中时,它将被注入为 ' '。因此,该语句用于进行该检查。
- expect(element.html()).toContain(“This is AngularJS Testing”) – 这用于指示 expect 函数应该找到元素(在我们的例子中是 div 标签)以包含“This is AngularJS Testing”的 innerHTML 文本。
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 页面上可能出现的任何其他内容的测试。
让我们看一个例子来了解如何实现这一点。
在下面的示例中,我们将有一个使用 ng-repeat 指令创建数据表的 AngularJS 应用程序。
- 我们首先创建一个名为“tutorial”的变量,并一次性为其分配一些键值对。显示表格时,每个键值对都将用作数据。然后将 tutorial 变量分配给范围对象,以便可以从我们的视图中访问它。
- 对于表中的每一行数据,我们都使用 ng-repeat 指令。该指令使用变量 ptutor 遍历教程范围对象中的每个键值对。
- 最后,我们使用标签以及键值对(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 安装量角器库。这可以通过在命令提示符中执行下面一行来完成
"npm install protractor"
我们的测试代码如下所示。
代码将放在一个名为 CompleteTest.js 的单独文件中,该文件将放在测试文件夹中。下面的代码只执行以下关键操作
- 浏览器功能由量角器库提供,并假定我们的 AngularJS 应用程序(使用上面显示的代码)正在我们的网站 URL 上运行 - http://localhost: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('http://localhost:8080/Guru99/'); }) it('Check the ng directive', function() { var list=element.all(by.repeater(ptutor in tutorial')); expect(list.count()).toEqual(3); }); });
上述测试将在 karma 浏览器中运行,并给出与上一主题中显示的相同的通过结果。
结语
- AngularJS 中的测试是通过使用 Google 自己开发的框架 karma 框架实现的。
- karma 框架使用 node 包管理器安装。基本测试需要安装的关键模块是 karma、karma-chrome-launcher、karma-jasmine 和 karma-cli。
- 测试写在单独的 js 文件中,通常保存在应用程序的测试文件夹中。这些测试文件的位置必须在名为 karma.conf.js 的特殊配置文件中提及。Karma 在执行所有测试时使用此配置文件。
- Karma 也可以用来测试控制器和自定义指令。
- 对于端到端 Web 测试,需要通过 Node 包管理器安装另一个名为 protractor 的框架。该框架提供了一些特殊方法,可用于测试 HTML 页面上的所有元素。