上篇中的契约测试解决了我们对微服务之间协作、交互的验证需求。本达人课到目前为止介绍的测试都是后端或者 API 级别的测试,可以说都属于“白盒测试”。自动化测试的最后一步,就是所谓的端到端测试(End-to-End Test),又称黑盒测试,即从用户角度验证整个系统的功能,看其从启动到结束是否全部符合用户预期。

黑盒测试:又被称为功能测试、数据驱动测试或基于规格说明的测试,是通过使用整个软件或某种软件功能来严格地测试, 而并没有通过检查程序的源代码或者很清楚地了解该软件的源代码程序具体是怎样设计的。测试人员通过输入他们的数据然后看输出的结果从而了解软件怎样工作。简单来说,它的测试视角是从最终用户出发,对系统的底层实现一无所知。

本文首先将讲解端到端测试的主要方法,包括配置步骤和测试用例的编写等。但是正如很多读者经常遇到的,UI 测试常常是非常脆弱、不稳定的,往往会因为一点点 UI 的变化而失败。为了确保端到端测试起到既能弥补其他测试的不足,又不会经常导致误报的作用,本文还将着重分析一些优化端到端策略的方法。

端到端测试的实施方法

UI 测试的框架和工具目前有很多。本文将着重以网页端的端到端测试为例。按照 GitHub 上的 Star(点赞)数目排名,目前最靠前的五个端到端测试框架为:

  • Nightwatch.js — 8206 个 star,765 个Fork(分支);
  • Protractor — 7569 个 star,1981 个Fork;
  • CasperJS — 6337 个 star,993 个Fork;
  • TestCafe — 4743 个 star,246 个Fork;
  • CodeceptJS — 1695 个 star,246 个Fork;

本文将选用 AngularJS 团队所发布的 E2E 测试框架 Protractor,过程如下图所示:

实施步骤主要分为以下几步:

  1. 编写配置文件和基于 Jasmine/Mocha/Cucumber 的测试用例;
  2. 使用Protractor作为执行框架;
  3. 调用Selenium Server/chrome Driver,启动浏览器进程;
  4. 从浏览器执行测试用例,检查 AngularJS 应用程序的结果是否符合预期。

下面将逐步加以介绍。

Protractor 简介

Protractor 是 AngularJS 团队发布的一款开源的端到端网页测试工具,可以说是专门为 Angular 定制,内置了各种可以选择、操作 Angular 元素的便捷方法。如果基于 Angular 开发,使用它可以减少很多重复代码。

Protractor的主要特点有:

  • 基于 Node.js 的程序;
  • 使用 Jasmine 测试框架测试接口,针对 AngularJS 的应用程序;
  • 用户还可以自由选择用 Jasmine 还是 Mocha 来编写是测试用例。

Jamine 是一个由行为驱动的 JavaScript 代码测试框架,不依赖于任何其他 JavaScript 框架,也不需要使用 DOM。它的语法非常简单、清晰,非常便于撰写测试用例。一个典型的 Jammine 测试用例如下:

其主要功能有:

  • 模拟真实的用户操作行为;
  • 针对 AngularJS 中的 Element 不需要做特殊的处理,普通 HTML 元素也同样支持;
  • 支持智能等待,不需要为页面中的加载和同步显示做特殊的等待时间处理
  • Protractor 的 webdriver-manager 将 WebDriver 统一管理,减少测试人员在使用过程中针对 WebDriver 的管理操作,将主要精力集中于端到端测试。

环境安装主要有以下几步:

  • 首先必须安装执行环境 Node.js。
  • Protractor 3 支持 Node.js v4 以上;
  • 使用 Node.js v0.12,需要使用Protractor 2
  • 安装浏览器,推荐 Chrome。
  • 安装 Protractor+WebDriver。
  • 安装完成后执行 protractor --version,检查安装是否正常。
  • 在命令行控制台启动 Selenium 测试服务器。

默认情况下,Selenium 测试服务器接入地址为:http://localhost:4444/wd/hub。

  • 输出测试报告需要安装相关插件,以便在结果目录中输出 HTML 报告
  • 输出 JUnit 格式的 XML 报告。

由于需要在 config 文件中加载。一般把这两个插件放在根目录的 node_modules 目录下

配置文件

配置文件位于根目录下,默认命名为 protractor.config.js,举例如下:

编写测试用例

测试用例的作用主要是:

  • 找到页面上的某个元素;
  • 通过某种方式同它交互;
  • 证实交互成功;
  • 重复上述过程直到测试结束。

查找页面元素

首先,介绍针对浏览器的常用操作:

其次是定位页面元素,Pratractor 支持用 by.binding 定位元素,又称为定位器 locator。Protractor 中常用的定位器有如下几种:

  • By Class Name

“class” 是 DOM 元素上的一个属性。在实践中,通常是多个 DOM 元素有同样的 class 名,所以通常用它来查找多个元素。

  • By Tag Name

根据元素标签名查找。

  • By Name

查找 name 属性匹配的表单元素。

  • By Link Text

查找链接文字匹配的链接元素。

  • By Partial Link Text

查找链接文字部分匹配的链接元素。

  • By CSS

正如名字所表明的,它通过 CSS 来定位元素。默认使用浏览器本地支持的选择器,可参考 W3C 的 CSS 选择器。如果浏览器默认不支持 CSS 查询,则使用 Sizzle。IE6、7和 Firefox 3.0 都使用了 Sizzle。注意使用 CSS 选择器不能保证在所有浏览器里都表现一样,有些在某些浏览器里工作良好,在另一些浏览器里可能无法工作。

更多定位器请见参考资料。

  • By id

这是最高效也是首选的方法用于查找一个元素。UI 开发人员常犯的错误是,要么没有指定 id,要么自动生成随机 id,这两种情况都应避免。即使是使用 class 也比使用自动生成随机 id 要好的多。

操作定位到的页面元素

Protractor 中使用 element(locator) 和 element.all(locator) 来定位元素,前者是定位单个元素,后者是定位所有符合条件的元素。第一个方法如果找到则返回该元素,如果没找到则抛出异常。第二种如果找到则返回一个包含所有元素的列表,如果没找到则返回一个空数组。

定位到元素后能做哪些操作?常用操作举例如下:

关于 sendkeys 的使用,注意还可以支持下列键盘操作:

操作

效果

sendKeys(protractor.Key.CONTROL, 'a')

全选

sendKeys(protractor.Key.CONTROL, 'c')

复制

sendKeys(protractor.Key.CONTROL, 'v')

粘贴

sendKeys(protractor.Key.CONTROL, 'x')

剪切

下面,我们就可以编写一个实际的测试用例了。下面假设有一个本地的 Web 服务器,打开浏览器之后登录,然后验证一些特定信息是否符合预期,保存为 tc/e2e/scan.js

执行 Protractor

  • 执行 protractor tc/e2e/scan.js
  • 执行过程中,Protractor 会启动浏览器,显示真实的页面信息;
  • 执行结束时,Protractor 会自动把浏览器关闭,且 WebDriver 日志会记录本次执行过程中的日志信息。
  • Protractor 执行过程日志。
  • WebDriver 启动的 Selenium Server 中也会记录本次请求的相关日志。

调试技巧

  • 启动 Webdriver 服务器。
  • 运行(URL 为所要测试的页面)。
  • 按下 Tab 键,就可以试用任何的元素定位器。

优化策略

虽然端到端测试可以彻底检查整个系统是否符合用户预期,但是很多读者都会感觉到,这样的测试很容易失败,因为即使前端有一些微小的改动或者调整,都会导致很多测试用例的失效。因此,我总结出下面这几点优化策略:

  • 端到端测试应当尽量简洁。“简洁”的意思是说,它应当覆盖用户使用功能的核心路径(即通常所称的“Happy Path”),但是不需要覆盖太多的分支路径。力求 UI 测试的轻量化,才能降低维护成本。否则,整个测试团队就会陷入更新前端脚本的泥潭之中。
  • 谨慎地选择测试范围。如果某个特定的外部服务或者界面很容易导致测试随机出错,那么可以考虑将这些不确定性排除到端到端测试之外,再通过其他形式的测试加以弥补。
  • 通过“自动化部署”(Infrastructure-as-code)来提高测试环境的可重复性。在测试不同版本或者不同分支的产品时,自动化测试往往会因为测试环境的不同给出不同的测试结果。这要求环境必须具备可重复性,解决的途径就是通过脚本进行自动化部署,避免手动部署的影响。
  • 尽可能摆脱数据对于测试的影响。端到端测试的一个常见难题就是怎么管理测试数据。有些团队选择导入已有数据,以加快测试速度,避免了新建数据的时间,但是随着生产代码的变化,这些预先准备的数据必须要随之变化,否则就可能导致测试失败。为此,我比较倾向于在测试过程中新建数据,虽然花些时间,但是这样避免了数据维护的成本,也保证了对用户行为的全面测试。
  • Protractor 支持 Page-Object 的概念,即以页面为单位,把页面中的所有行为都记录为方法,存为一个 JS 文件;然后再在主测试用例中以 import 和 require 的方式加以调用。这样可以避免重复的代码和维护的工作量(一个页面的元素发生变化时只需要修改其对应的 Page-Obejct 即可,而不需要在所有用到这个元素的地方都做改动)。换句话说,在设计测试用例时,一定要考虑可扩展性(Scalability),避免将来的重复性工作。

下面是一个 Page Object 的例子:

然后在主测试用例文件中,用下面的方式调用:

  • 将测试用例划分到不同的测试组合(Test Suite)里面,根据需要调用。在写好测试用例以后,并不需要每次都全部加以测试,而是可以根据需要只测试其中有可能发生改动的部分。Protractor 提供的 Test Suite,可以满足这种需要。在下面这个配置文件例子中,加入几行即可:

本课总结

本课介绍了端到端测试的主要方法和优化策略,让您可以快速地开始对前端程序进行自动化黑盒测试。

主要方法有:

  • 环境配置
  • 页面对象抓取
  • 测试用例设计
  • 测试执行

优化策略有:

  • 保持简洁、轻量化
  • 慎重选择范围
  • 提高可重复性
  • 摆脱数据影响
  • Protractor 的一些使用技巧

到目前为止,我们已经覆盖了“自动化测试金字塔”的大部分内容。下一篇,我们将会介绍目前测试领域的两个新热点:云端测试和性能测试。