文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

Angular2-End-To-End-Testing

对于为什么要为我们的应用程序添加自动化测试,在过去我已经阐述过很多充分的理由了。其中一个原因就是效益和时间成本的取舍衡量我们很多时候是未知的,另外一个担忧就是很难把测试集成到现有的应用产品中去,我们怎样才能够无需重写代码仅仅引入测试就实达到测试产品的目标呢?

让我们先简要地甄别几种罗列在这里的测试方法。在各种各样的测试方法中最常见的两种就是单元测试和端到端测试(端到端测试也被称为集成测试)。单元测试是一种测试代码整体表现的测试方法,它不关心用户所看到的,但是确保你的代码是可行的。集成测试则是一种模拟用户行为的测试方法。例如,它可以自动模拟登陆系统,创建表单,登出系统。所有这些都是自动执行的,因此你能直观地观察发生了什么。

第 1 段(可获 2.3 积分)

这两种测试方式通常会互相结合使用,对于新的应用产品来说这是理想的。但如果时间紧迫或者你的项目是继承自原有的项目,那么端到端测试会比单元测试更加适合,这源于我们一开始无需依赖对原有项目代码库的太深入的理解。我们也可以比单元测试更快速的覆盖更多的测试场景,因为他们不会去测试单一单元。

  单元测试仍然是很重要的,但是如果你不得不从中择其一的话,端到端测试或许是一个更好的选择。在本文,我们将会对一个现有的Angular 2应用进行测试,我们会使用集成测试并且覆盖多个应用场景。

第 2 段(可获 1.64 积分)

如果你还不熟悉Angular 2,可以查看这个链接Angular 2 article from Jscrambler.

被测试的场景

  • 当初始加载应用时,在待办事项清单中有三个事项
  • 我们可以添加一个新的待办事项。
  • 我们能够点击这个待办事项并且跳转到详情页。
  • 能够删除一个待办事项
  • 能够编辑待办事项并且保存后在主页能看到变化
  • 不能够保存一个空的待办事项,在点击无效的保存按钮后待办事项列表应该保持相同的长度
  • 初始化加载主页的时候,添加按钮应该点击无效
  • 只有在我们开始编辑事项标题时,才能让保存按钮点击有效
第 3 段(可获 1.98 积分)

待办事项应用程序概述

让我们简要的描述一下我们的应用。应用首先在主页初始化一个待办事项清单列表,准确来说是三条事项。数据并非来自服务器,而是从一个硬编码的文件中加载。

在主页,我们能添加事项,也能通过点击标题浏览对应的事项详情页。在详情页,我们能够编辑事项标题或者删除事项。

复制和安装这个待办事项应用程序

  • .复制我存放这个仓储 here  未测试的应用程序,首先要先确保你是在master分支。接着,为了顺利完成后面的步骤,你需要安装几个工具。截止本教程, Angular 2已经发布了候选版本,当前是版本2
  • 确保你已经安装了Node 4.x.x以上版本的NodeJS。
  • 当使用复制的仓库时,使用下面的命令安装node依赖:
    npm install
  • 使用 Angular-CLI做了扩展,请用下面的命令全局安装 Angular-CLI:
    npm install -g angular-cli@latest
  • 端到端测试要用被叫做 protractor  的工具运行,全局安装protractor :
    npm install -g protractor
  • 安装完所依赖后,启动服务程序:
    ng serve
    并且导航到这个浏览器地址: http://localhost:4200,在这里你应该能看到那三个待办事项
第 4 段(可获 2.66 积分)

如果启动服务出现问题,可以参考stackoverflow issue 尝试解决问题。

引入Angular 2测试概念

 端到端测试存放路径为e2e,这里已经有一个叫es2/app.e2e-spec.ts的测试程序

测试采用jasmine框架编写,这里有很多模块化和组织化的Angular 2测试方案,但这个是最简单的。我们会采用这种方法在一个文件中进行所有测试。

我们的应用仅仅关心待办事项,出于满足好奇心的缘故,和那些想要比上面更加复杂的东西的人,让我们假设一个更为复杂的应用场景:一个包含订单和用户配置文件的复杂应用。我采用的方法是在e2e文件夹中为每一个部分新建一个文件夹,然后把各自的测试程序放在相应的文件夹。

第 5 段(可获 2.05 积分)

这时候,我i门有e2e/orders和e2e/userProfile两个文件夹。在每个文件夹可以只要一个测试文件,如果需要也可以有多个测试文件,要谨记的是每个测试文件的命名都必须以e2e-spec.ts结尾,否则protractor测试器会抓取不到这个测试文件。

好的,回归简单的情形,只有一个测试文件的测试。如果看一下这文件,你会在头部看到一条导入语句,导入的正是已经写好的测试方法。但在本文中,我们不会这样做,把它看作一个库函数。

第 6 段(可获 1.63 积分)

导入语句之后,有一个描述模块,描述块里面的是回调函数,包含beforeEach和it两个方法。传递给beforeEach的回调方法会在每次测试中被调用。

独立的测试则放在传递给it方法的回调函数里面。

让我们用下面的命令来运行测试程序:

protractor

如果在运行protractor时出现问题,运行下面的任意一条命令,或者参考here

./node_modules/protractor/bin/webdriver-manager update

或者

webdriver-manager update

如果你在主页看到“app works”,当前测试应该是失败的。事实并非如此,因为我们已经修改了主页的内容。

第 7 段(可获 1.43 积分)

在开始编写测试之前,让我们先理解一些重要的通用函数,再使用 Angular 2 的端到端测试。

导航到页面

在测试文件中,有一个browser全局变量。它使用import语句引入

import { browser, element, by } from 'protractor/globals';

你可以现在添加。

例如,我们使用下面语句导航到你的应用程序中可用的任一页面

browser.get('/');

导航到主页,以及

browser.get('/users');

导航到users页面。请注意,这些URL是相对的。虽然我们也可以使用绝对URL,但是我还是建议使用相对URL,因为如果你的域名改变,这更易于维护。

第 8 段(可获 1.45 积分)

选择元素

通常的做法是在当前页面上选择元素。你可以通过一个叫做element的全局变量选择元素。它接受可以使用全局by创建的定位器。

使用选择具有green类的p标签例子如下

let greenParagraph = element(by.css('p.green'));

选择多项元素,你需要做轻微变动:

let greenParagraphs = element.all(by.css('p.green'));

这将给出一个数组,而不是一个单一的元素。

抓取元素文本

要得到一个元素的文本,你必须先选择它,然后调用getText方法,如下所示。

第 9 段(可获 1.31 积分)
let greenParagraph = element(by.css('p.green'));
let text = greenParagraph.getText();

点击元素

可以使用下面的语句触发点击元素的事件

let submitButton = element(by("form .submit-button"));
submitButton.click();

统计元素

我们能够使用以下语法统计元素个数

let blueParagraphsList = elements.all(by("p.blue"));
let count = blueParagraphsList.count();

测试场景

有了以上的概念,让我们来完成之前列举的测试场景

确认我们最初有三个待办事项

当应用程序初始加载时,我们在列表中有三项待办事项

第 10 段(可获 0.76 积分)

在测试文件e2e/app.e2e-spec.ts中,删除beforeEach模块中it函数的回调方法,然后在这里添加:

it("should show three todos when we first load the todo app", () => {
  browser.get("/");
  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(3);
})

不要忘记在头部添加导入语句:

import { browser, element, by } from 'protractor/globals';

现在当你运行protractor 命令时,另一个浏览器窗口将会快速地打开和关闭,在你的控制台能够看到一个绿色高亮的通过测试

第 11 段(可获 0.8 积分)

好的!我们已经完成一个可通过的Angular 2端到端测试

新建待办事项

现在进行下一个任务,我们要能新建待办事项,让我们使用下面的代码添加另一个it测试模块:

it("should be able to add a new todo", () => {
  browser.get("/");
  let newTodoInput = element(by.css(".add-todo input[type=text]"));
  newTodoInput.sendKeys("Todo 4");

  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  newTodoSubmitButton.click();

  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(4);
})
第 12 段(可获 0.54 积分)

我们在这里要做的是在待办事项输入框中输入文本并提交表单。然后我们检查是否有四个待办事项。 如果是的话,测试通过。

我们刚刚介绍了另一个函数sendKeys,它可以访问一个选中的元素,常用于输入文本到输入框这类元素中。

查看待办事项详情页

我们可以单击一个待办事项,然后转到该待办事项的详情页,我们可以通过以下测试来实现。

it("should be able to click on a todo on the homepage and get to the details page", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();
  let firstTodoText = firstTodo.getText();

  firstTodo.click();
  let inputFieldText = element(by.css("todo input[type=text]")).getAttribute("value");

  expect(inputFieldText).toEqual(firstTodoText);
})
第 13 段(可获 1.18 积分)

删除一个待办事项

我们应该能删除一个待办事项。现在让我们尝试删除一个然后看看能否成功

我们将会导航到todo页,点击delete按钮,当我们返回主页时,将会少了一个待办事项。

it("should be able to delete a todo", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();

  firstTodo.click();

  let deleteLink = element(by.cssContainingText("span", "Delete"));
  deleteLink.click();

  let todosList = element.all(by.css(".todos .todo"));

  expect(todosList.count()).toEqual(2);
})
第 14 段(可获 0.63 积分)

编辑一个待办事项

我们应该可以编辑一个待办事项的标题,保存后在主页的列表中能够看到变化

it("should be able to edit a todo title", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();

  firstTodo.click();

  let todoInputField = element(by.css("todo input[type=text]"));
  todoInputField.clear();
  todoInputField.sendKeys("Editted Todo1 Title");

  let saveButton = element(by.css("todo button[type=submit]"));
  saveButton.click();

  firstTodo = element.all(by.css(".todos .todo")).first();
  let firstTodoText = firstTodo.getText();

  expect(firstTodoText).toEqual("Editted Todo1 Title");
})
第 15 段(可获 0.39 积分)

不能保存空的待办事项

尝试保存一个空的待办事项的行为应该被禁止,并且在点击了无效的按钮后待办事项列表应该保持相同的长度

it("should not be able to save an empty todo", () => {
  browser.get("/");
  let newTodoInput = element(by.css(".add-todo input[type=text]"));

  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  newTodoSubmitButton.click();

  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(3);
})

初始化时保存待办事项按钮被禁用

第 16 段(可获 0.51 积分)

初始化时新建待办事项按钮应该无效,所以添加下面的几行代码:

it("should have add todo button be disabled initially", () => {
  browser.get("/");
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));

  expect(newTodoSubmitButton.isEnabled()).toEqual(false);
})

当我们开始编辑输入,激活保存待办事项按钮

保存按钮应该只在我们开始输入后才有效

it("should only enable save todo button when we start typing a new todo title", () => {
  browser.get("/");
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  let newTodoInputField = element(by.css(".add-todo input[type=text]"));

  newTodoInputField.sendKeys("New Todo 4");

  expect(newTodoSubmitButton.isEnabled()).toEqual(true);
})
第 17 段(可获 0.49 积分)

结论

现在,我们来总结一下 Angular2 的“端对端”测试。即使您没有任何的编程基础,也可以快速上手编写“端对端”测试。对于那些被引入代码库而又可能存在漏洞的部分,“端对端”测试是一个高效便捷的方法来捕获问题所在。

我们在概念部分中介绍了一些其他方法。您可以点击这里来浏览这些 Protractor API。并且可以在 GitHub repository 上找到这个应用的完整版和测试版。

我希望您看完这个介绍之后,在您修改任何一行代码之前都能愉快地开始您的前端应用测试。如果您愿意,可以和我们分享一些您在日常测试中积累的经验,或对于 Javascript 框架及 Angular2 的想法。感谢您的阅读。

第 18 段(可获 1.95 积分)

文章评论