如何用Protractor和Jasmine测试Angular应用程序

166 阅读9分钟

使用Protractor和Jasmine测试Angular应用程序

在软件开发的世界里,测试是一种确保具有一套既定功能的应用程序能够不折不扣地执行这些功能的方法。它涉及到通过手动或使用自动化工具对你的软件进行一系列的检查,以验证其有效性。

在开发软件时,难免会出现错误。测试使这些错误有可能在软件发布之前被发现并得到纠正。

一个经过良好测试的软件是可靠的,安全的,并且是高度负责的。从长远来看,它可以节省成本,有助于防止人力和资源的浪费。

在本教程中,我们将使用Protractor和Jasmine来测试一个基于AngularJS的网站。

前提条件

要完成这篇文章,你必须对以下内容有充分的了解。

  • DOM元素的层次结构和操作
  • 基本的JavaScript和异步操作
  • AngularJS框架

术语

  • [AngularJs]是一个开源的javascript框架,用于构建前端应用程序。
  • [Jasmine]是一个开源的、行为驱动的开发框架,用于测试JavaScript代码。
  • [WebDriver Js]是[Selenium]的官方Javascript实现。它有助于与网络上的元素互动。
  • [Protractor]是一个建立在WebDriverJs之上的NodeJS程序,它支持Jasmine测试框架,被用作测试Angular应用程序的端到端测试框架。Protractor通过实现浏览器上可能的用户事件的自动化和交互,扩展了WebDriverJs所能做到的。
  • 端到端测试指的是对通过组成Angular应用流程的各个模块发生的操作进行的测试。

例如,测试注册页面,到登录页面,到个人资料页面,以及注销可以是一个端到端的测试流程。而这里的每个模块都有其单元测试案例。

为什么是protractor

如果你打开一个非矩形的网页,你有用户可以互动的元素,如输入字段、下拉标签或可点击按钮。所有这些元素都可以用Selenium网页框架来测试。

使用AngularJS构建的网站引入了额外的DOM属性,这些属性只有Angular应用程序可以识别,如 "ng-model"、"ng-repeater "或 "ng-controller"。

这些属性包裹着现有的HTML DOM元素。这些属性对于Selenium的测试是不可见的。

Protractor可以实现对这些隐藏元素的捕捉。

此外,protractor还提供了一些函数,如waitForAngular,by.binding,WebElement.evaluate ,等等,这些函数为你的测试提供了多种选择。

Selenium WebDriver处理了很多与使用裸Selenium有关的同步问题。另一方面,Angular(像纯Javascript)异步工作,利用承诺来处理回调。

为什么选择Jasmine

Jasmine是一个记录良好的开源JavaScript行为驱动测试框架,不依赖浏览器、DOM或任何JavaScript框架。

我们有几个测试框架,如Jest和Mocha。

推荐Jasmine而不是其他的,因为AngularJS CLI默认带有Jasmine作为测试运行器,而且相对容易学习。

然而,你仍然可以配置其他测试框架来测试Angular构建的Web应用程序。

套餐

一个套件定义或描述你的测试案例。

一个套件由一个描述函数来识别。describe() 将规范分组,就像将系统的一个组件或一组动作分组一样。

我们将第一个参数设置为一个字符串,作为在函数体中定义的测试用例的标识符。

比如说

describe("A String that specifies a suite", function () {
	it("Contains an expectation", () => {
		let value = true;
		expect(value).toBe(true);
	});
});

规范

你可以使用一个名为it() 的全局函数来定义一个规范(spec)。

it() 是类似于 ,它接受一个字符串作为它的第一个参数,一个函数作为它的第二个参数。describe()

字符串参数决定了规范的标题,当有多个规范存在时,它被用来识别该规范。

另一方面,函数定义了一个测试。

一个规范可以包含多个使用 "期望 "语句(将在后面讨论)描述的期望,该语句用于测试代码的状态。

一个具有原始结果的测试用例的期望值可以是真,也可以是假。

it() 简而言之,它是一个包含可执行代码的函数,用于执行所需的测试。

由于Jasmine是一个JavaScript测试框架,变量范围的适用方式与vanilla JavaScript代码的适用方式相同。

在一个函数中定义的变量是本地的,只在该特定函数中可见。这有助于在it() 块内进行数据共享。

如果你想在其他测试块之间共享数据,只需使用一个全局变量。

期待值

期待是接收结果和预期值的函数。这些函数决定一个测试是成功还是失败。

匹配器

匹配器是一个布尔结果的实现,即匹配器的结果确认某些东西是真还是假。

在这种情况下,它根据给定的结果/值检查期望的结果。这决定了一个测试用例是通过还是失败。

在Jasmine中,你会发现有几个匹配器可以帮助你实现预期的测试场景。

设置和配置

首先,下载并安装[NodeJS]。

接下来,我们全局安装protractor。

npm install -g protractor

然后运行下面的命令来更新webdriver管理器。

webdriver-manager update

在Angular应用程序的根目录下创建一个conf.js 文件,并添加以下代码。

exports.config = {
   directConnect: 'http://localhost:4444/wd/hub',
   specs: ['./*-spec.js’],
   framework: ‘jasmine’,
};
  • directConnect: true 选项指定了与Selenium服务器互动的主机(seleniumAddress)。除非指定,否则它将使用默认配置。Chrome将被作为默认浏览器使用。
  • specs 的选项应该是测试时运行的规范JavaScript文件的路径。
  • framework 属性指定了我们使用的测试框架。这里,是Jasmine。
  • 上面代码中规格的值告诉protractor检查当前目录,并执行所有以字母-spec.js 为结尾的文件。

在根目录下创建一个test-spec.js 文件。

在这里,我们指定测试用例。

如果Jasmine还没有安装的话,把它作为一个依赖项来安装。

npm install --save-dev jasmine

在终端上,导航到conf.js 文件所在的目录,运行下面的命令,开始你的测试。

protractor conf.js

测试

在本教程中,我们将测试一个名为Blender的流行网站;使用AngularJS构建。

由于这个网站是用AngularJS建立的,我们将利用Protractor来捕获我们需要操作的元素。

在这里,我们将捕获位于页面右上角的 "搜索输入 "元素。

然后,我们将通过使用protractor的API来进行 "免费 "视频的搜索请求。

最后,我们将验证DOM的互动。预计Video-blender会有可用的免费视频,在DOM页面布局中列出这些免费视频,同时替换初始网页。

对一个不存在的词进行另一次搜索,也应该产生变化,显示搜索的结果。

首先,我们将创建describe() ,这个函数将容纳我们的测试。这个字符串指定了我们要写的这个测试块的名称。第二个参数是一个函数,我们的规格将被写入其中。

describe("Testing exercise for protractor and Javascript application", function () {});

注意,该函数是一个异步函数,参数为 "done"。

这说明这个函数中的一些操作不会在第一时间发生,而是可能在以后通过停止操作流发生。这样的操作会用await 关键字来标记。

done() 方法是传入函数的参数的函数调用器,在所有测试结束时被调用,以标记测试规范的结束。

describe("Testing exercise for protractor and Javascript application", function () {
	it("Navigate to Blender Video search for videos", async function (done) {
		done();
	});
});

在下面的代码中,我们首先将一个字符串(网站URL)保存到变量 "url "中。我们利用protractor的API方法browser.get() 来请求指定的链接。

我们将这个函数指定为await ,以异步处理。

describe("Testing exercise for protractor and Javascript application", function () {
	it("Navigate to Blender Video search for videos", async function (done) {
		let url = "https://video.blender.org/";
		await browser.get(url);
		done();
	});
});

在这里,我们写了我们的第一个测试案例。

我们期待网站的主页被加载。为此,我们也利用了protractor的API方法browser.getCurrentUrl()

现在,我们使用浏览器检查工具从DOM中抓取我们需要执行进一步测试的元素。

基于该元素,你可以使用获取信息。

  • id
  • class
  • xPath
  • CSS选择器
  • 标签

我们抓取的是搜索输入元素searchBar ,搜索按钮点击searchButton ,以及结果元素searchResult

describe("Testing exercise for protractor and Javascript application", function () {
	it("Navigate to Blender Video search for videos", async function (done) {
		let url = "https://video.blender.org/";
		await browser.get(url);

		expect(await browser.getCurrentUrl()).toBe(url);

		let searchBar = element(by.css("#search-video"));
		let searchButton = element(by.css(".icon-search"));
		let searchResult = element(by.css(".search-result"));

		done();
	});
});

对于 "searchBar",我们输入一个字符串值,以free 。如果是这样,对 "searchButton "变量做一个点击动作。

我们希望 "searchResult "元素在搜索完成后在页面上是可见的,因此我们测试css样式的存在"display":"block"

describe("Testing exercise for protractor and Javascript application", function () {
	it("Navigate to Blender Video search for videos", async function (done) {
		let url = "https://video.blender.org/";
		await browser.get(url);

		expect(await browser.getCurrentUrl()).toBe(url);

		let searchBar = element(by.css("#search-video"));
		let searchButton = element(by.css(".icon-search"));
		let searchResult = element(by.css(".search-result"));

		searchBar.sendKeys("free");
		searchButton.click();

		expect(searchResult.getCssValue("display")).toBe("block");

		done();
	});
});

然后我们对不存在的搜索结果 "随机 "做进一步的测试。

我们不清除搜索栏中的文本,因此我们的搜索被附加到搜索栏中现有的 "自由 "文本中。

如果你想清除搜索栏,在搜索一个新的关键词之前,我们要做以下工作。

searchBar.clear().then(function () {
	searchBar.sendKeys("random");
});

结果将是一个空的页面,因为我们没有找到基于该搜索的元素。

describe("Testing exercise for protractor and Javascript application", function () {
	it("Navigate to Blender Video search for videos", async function (done) {
		let url = "https://video.blender.org/";
		await browser.get(url);
		expect(await browser.getCurrentUrl()).toBe(url);
		let searchBar = element(by.css("#search-video"));
		let searchButton = element(by.css(".icon-search"));
		let searchResult = element(by.css(".search-result"));

		searchBar.sendKeys("free");
		searchButton.click();

		expect(searchResult.getCssValue("display")).toBe("block");

		searchBar.sendKeys("random");
		searchButton.click();

		expect(searchResult.getCssValue("display")).toBe("block");

		done();
	});
});

在运行该代码时,你应该看到一个Chrome浏览器窗口打开了。导航到指定的网页,执行搜索并进行测试。

测试输出应该是。

1 test, 1 assertion, 0 failures

祝贺您首次使用Protractor进行测试!

总结

在本教程中,你已经了解了什么是测试,为什么测试很重要,以及测试中所用术语的各种定义。

此外,我们还了解了从DOM中提取元素并测试其结果的基本代码。

有几个选项可以捕获DOM元素进行测试。Protractor就是这样一个用于测试Angular应用程序的框架。