在构成 软件测试金字塔 的所有类型测试中,端到端 UI 测试被认为是最难管理、执行速度最慢、最不稳定、最易出错,有时甚至完全不切实际的测试。看看 ThoughtWorks 博客 上最近的一篇文章——作者回忆起一个工程团队被问及他们的 UI 测试状态时给出的答案:

"嗯,我们有一些 Selenium 测试,但它们很脆弱。它们似乎总是出错,所以我们很少运行它们。

不仅如此,仅仅从 Cypress 项目团队在 他们的网站 上写的内容来看,似乎软件测试在软件开发人员中并不享有良好的声誉:“测试很糟糕。这是每个开发人员都害怕的那部分。”

是什么让 UI 测试如此脆弱,并让开发人员“害怕”?Cypress 团队还声称,前端测试在过去十年中没有发展,至少没有像网页开发那样快速发展。

互联网更快捷,但网站却没有

首先,网页开发在过去十年中并没有真正发生太大变化,或者说,这取决于你对“发展”的定义。当然,有 webpack、React 和 ES6,但根据 httparchive.org 的数据,过去十年中网页的平均加载时间基本保持不变,尽管互联网速度一直在稳步提升,硬件技术也在快速进步。因此可以说 互联网更快捷,但网站却没有。此外,正如 Skypack 工具背后的团队指出的那样,“构建网页从未如此复杂。”

考虑到这一点,我可以很自信地断言,实际上网页开发并没有真正发生太大变化,尽管我们现在拥有更好、更复杂的工具。另一方面,前端测试确实在多个方面发生了发展,并且仍在不断发展,也许比网页开发本身发展得更快。

编码与测试

开发人员之所以“害怕”测试,仅仅是因为整个软件行业都采用了软件开发过程的二元论观点。我们这边有开发人员,他们总是被承诺可以构建很酷的东西,可以尝试最新的技术等等,而我们这边有测试和质量保证,开发人员往往认为测试和质量保证太过乏味且缺乏趣味性。

要让开发人员相信软件测试和前端开发一样令人兴奋和酷炫,需要一些想象力的发挥。只要开发和测试之间的这种二元性仍然存在,开发人员害怕测试部分(也许质量工程人员也害怕开发人员对持续变化和光鲜外表痴迷),测试就会继续脆弱和易出错,这将导致整体质量下降。

我将尝试说明的是,编码和测试不是两个相互独立的活动。测试是软件开发不可分割的一部分,就像编码一样。每个认为测试不是他们的工作内容的开发人员,实际上仍然在进行某种形式的测试。只是他们没有以自动化的方式进行,而是以手动、乏味且有些随机的方式进行。

使用 Nightwatch 进行 UI 自动化

大约十年前,当 Node.js 发布时,几乎没有使用 JavaScript 进行端到端测试的工具可用,而那些存在的工具需要花费大量精力才能有效地设置和使用。然而,如今,有几个由 Node.js 提供支持的 UI 测试框架,它们都承诺提供快速安装、用 JavaScript 编写的稳定测试。

当然,那些你必须花上几个小时,甚至几天来设置 UI 自动化项目的时代已经过去了。使用 Nightwatch,现在只需要一两分钟就可以开始一个使用 Chrome、Firefox、Safari 的测试自动化项目,其中包含对 Selenium Grid 和 Browserstack 的内置支持。可以轻松添加其他服务。

但是测试仍然脆弱或易出错吗?是的,这是 UI 测试,特别是 Selenium 测试中最常用的两个形容词。在 Nightwatch 中,现在基本上可以从一个开源框架中获得你对减少测试运行过程中脆弱性和易出错性的所有期望,例如元素的隐式等待、断言失败的自动重试、测试用例失败的重试、网络错误的重试等等。我们的计划不仅仅是试图检测和减轻易出错性,而是让它变得不可能。

什么是反馈循环?

反馈循环是一个迭代活动,由以下步骤组成:计划、编码、验证、退出——规划代码更改、实施代码更改,然后验证结果是否符合预期。

反馈循环存在于软件开发乃至其他领域。我第一次从一位同事那里听说过反馈循环,他在 2010 年的 jQuery 大会上做了 一次演讲。反馈循环是敏捷软件方法论中的一个常见概念,但同样的概念也存在于控制理论、生物学、数学、工程学等等。甚至地球的 气候系统 也存在反馈循环。

认知科学的奠基文本之一《计划与行为结构》(1960 年)将反馈循环的早期形式引入,作为人类行为的基本单元。作者确定了以下步骤:测试-操作-测试-退出,构成一个 TOTE 单元。正如他们所描述的,“在最弱的形式下,TOTE 仅仅断言,生物体执行的操作不断受到各种测试结果的指导。” 1

The TOTE unit
TOTE 单元

反馈循环是神经系统 2 的基本组成部分。这让我回到我之前的观点,即每个说他们不在流程中进行测试的开发人员,实际上仍然在进行某种形式的测试。我们必须完成的任何任务,无论是实现新功能还是修复错误,这个过程至少涉及一个反馈循环——一个 TOTE 单元,通常包含多个迭代。

完成任务

这是一个例子。 Browserstack 是 Nightwatch 用户的热门选择,他们希望在包含多个桌面和移动浏览器的分布式云基础设施上运行他们的测试。

假设你是一名开发人员,正在构建 Browserstack Automate UI 仪表盘,你的任务是让一个新的 Nightwatch 测试实时显示在列表中。

考虑到上面的 TOTE 单元,测试阶段将非常复杂,需要执行几个不同的操作才能断言该功能是否成功实现(停止循环的条件)。其中甚至有一些子反馈循环。

The TOTE unit
将新功能实现为 TOTE 单元

实施更改后,你需要执行验证过程的以下手动步骤:

  1. 确保本地开发服务器正在运行
  2. 对本地开发后端执行示例测试脚本
  3. 打开浏览器并导航到本地开发 URL(或重新加载页面)
  4. 检查测试脚本是否显示在仪表盘列表中

如何缩短反馈循环

实施阶段在每次迭代中都是可变的,但测试阶段相当固定,每次都涉及相同的步骤,花费的大致精力也相同。因此,如果我们设法缩短测试阶段,不仅执行起来会更简单,而且时间也会更短。

幸运的是,现在我们可以自动化准备阶段中涉及的所有手动步骤,我们还可以添加一个测试断言来验证条件是否满足(执行的测试脚本是否显示在仪表盘列表中)。然后,反馈循环的实际测试阶段将仅包含运行这个新创建的自动化脚本。

The TOTE unit
自动化测试阶段

演示项目

如果你仍然不相信,也许 这个演示项目 会有所帮助,它可以在 Github 上获得。该项目包含我上面描述的实验的所有代码。

beatfactor/nightwatch-feedback-loops - GitHub

我已经包含了公共 URL 以便有一个工作示例,但当然,在实施阶段,将使用开发服务器代替。

以下是主要的端到端测试所做的工作:

  1. 对 browserstack.com 服务进行登录
  2. 保存维护后续测试运行会话状态所需的 cookie
  3. 在子进程中启动第二个 Nightwatch 测试
  4. 断言第二个测试是否在 Browserstack 仪表盘的列表中找到。

通过使用这种技术,你不仅可以缩短反馈循环,而且在完成任务后,你还会得到一个端到端测试,它可以用于回归测试和持续集成。

  1. 乔治·A·米勒、尤金·加兰特、卡尔·H·普里布拉姆——计划与行为结构(亨利·霍尔特公司,1960 年)第 39 页 ↩︎
  2. 诺伯特·维纳在《控制论或动物和机器中的控制与通信》(纽约:Wiley,1948 年)中提出的“控制论假说” ↩︎