跳到主要内容

如何自动化视觉回归测试

发布产品或功能时最大的麻烦之一是代码库中的回归。两周前运行良好的一些功能现在已经被打破 - 而且始终是发现问题的客户端。没有自动化测试,你注定要么:

  1. 花费太多时间手动测试每个更改的功能
  2. 在不知不觉中破坏现有功能的风险更大

尽管有这方面的知识,我们很多人都不打算编写自动化回归测试,因为我们觉得设置和维护工作太多了。幸运的是,这已经改变了。我们现在可以使用称为视觉回归测试的技术编写相当全面的测试。

功能停止按预期工作时会发生回归。通常这在代码更改后发生,但也可能由于页面内容的变化或基于时间的条件(例如夏令时弄乱闹钟)而发生。

我们通过比较变化前后网站的外观(即差异)进行测试。这不是测试驱动的开发,您可以在其中编写测试,然后编写代码 - 而不是针对视觉输出本身进行测试。

入门

为了简单起见,我正在测试一个基本的登录屏幕。我分叉了整洁的小Plunkr由Jason Watmore撰写。我将在本地副本上进行测试,但我可以使用原始的Plunkr本身轻松测试。

有许多可用的测试工具,每个都有优点和缺点。例如,Wraith和BackstopJS非常适合快速测试大量页面。您只需添加要检查的页面的URL以及CSS选择器以关注并运行它。

这对于静态站点非常有效,但不会捕获现代Web应用程序的复杂性。在这些情况下,您需要深入研究测试脚本。这意味着要编写一系列操作 - 基本上,教导计算机浏览您的网站。 CasperJS非常适合这种情况,但不允许您在整个浏览器套件中进行测试。

The entire login page. It’s not necessary to capture every part of the page to have valuable tests

整个登录页面。没有必要捕获页面的每个部分以进行有价值的测试

为了捕捉我们所瞄准的全部测试范围,我们将依赖该行业多年来使用的工具:

安装Selenium

过去,使用Selenium意味着安装Java运行时并为测试用例编写一堆Java代码。谢天谢地,前端开发人员已经改变了。

对于熟悉npm的人来说,在本地设置Selenium现在很简单。感谢selenium-standalone,我需要做的就是在命令行中运行三个命令。

npm install -g selenium-standalone selenium-standalone install selenium-standalone start

这使我可以编程访问我的计算机上安装的浏览器,允许我使用WebdriverIO,一个npm模块,为Node.js提供Selenium绑定。我将使用一个名为的相关工具WebdriverCSS。 WebdriverCSS本质上是WebdriverIO的附加组件,增加了可视化回归测试。

要安装这两个,我从我的项目根文件夹的命令行运行npm install webdriverio webdrivercss。

写我的考试

现在我安装了所有东西并运行了Selenium,是时候编写我的第一个测试了。为了保持井井有条,我创建了一个'tests'文件夹,里面有一个名为'visual'的子文件夹。此文件夹将包含我们的测试和屏幕截图。然后我创建了一个名为“login.js”的空JavaScript文件。

我需要做的第一件事是加载WebdriverIO和WebdriverCSS。这是一个Node.js脚本,所以我将使用它的内置require语句:

var webdriverio = require('webdriverio'); var webdrivercss = require('webdrivercss');

接下来,我初始化WebdriverIO,并定义要测试的浏览器:

var client = webdriverio.remote({desiredCapabilities:{browserName:'firefox'}});

通过传入'firefox'作为browserName属性的值,我告诉WebdriverIO使用我的本地Firefox副本。 desiredCapabilities对象可以包含更多信息,尤其是在更高级的Selenium设置上进行测试时。但是,根据我的需要,这就是所需要的。

在开始我的实际测试用例之前还有一件我需要注意的事项。我需要初始化WebdriverCSS并定义一些用于存储图像的路径。

webdrivercss.init(client,{screenshotRoot:'tests / visual / baseline',failedComparisonsRoot:'tests / visual / failures',});

您可以更改路径以匹配您的设置,或者根据您的喜好将基线和故障重命名为不同的路径。重点是将它们全部保存在'tests / Visual /'文件夹中。

基本网站连接

现在一切都已建立,是时候编写实际的测试了。为此,我首先指定我正在测试的网站:

client .init()。url('http:// localhost:3000')。end();

还有一些围绕URL定义的初始化和清理代码,它向WebdriverIO指示应该何时启动和停止测试。

定义屏幕截图区域

现在进行实际测试。我将捕获登录表单的两个区域:页眉和表单本身。要定义它,我调用webdrivercss函数并传入我的详细信息。

client .init()。url('http:// localhost:3000')。webdrivercss('login form',[{name:'title',elem:'。container h2'},{name:'form', elem:'。enctainer form'}])。end();

登录表单,标题和表单都是用于生成屏幕截图的图像文件名的人性化名称。另一部分是elem属性。这是Selenium将用于查找您正在寻找的元素。

虽然为此使用CSS选择器很常见,但你也有全套选择策略可通过WebdriverIO获得。

比较变化

现在我们已经编写了测试脚本,是时候尝试一下了。我打开命令行备份并从我的项目根目录执行node tests / visual / login.js。我等了一两分钟才完成执行。在此期间,将弹出一个Firefox窗口,其中包含正在测试的网站,我可以在测试运行时观看。

Pink parts in the diff image highlight the changes between the before and after shots, making them easier to see

差异图像中的粉红色部分突出显示前后拍摄之间的变化,使其更易于查看

测试完成后,我将返回到命令提示符。最初看起来什么也没发生,但是当我打开'tests / visual / baseline'文件夹时,我现在有三个新图像:'login form.form.baseline.png','login form.title.baseline。 png'和'login form.png'。我们的主要焦点是'.baseline'图像。第三个图像更多地是被测试的整个页面的参考(如果我需要它进行调试)。

注意:如果您在Retina显示屏上运行测试,屏幕截图可能会关闭。这是一个已知问题使用WebdriverCSS。最好的解决方法是使用外部Selenium Grid提供程序BrowserStack要么酱汁实验室运行测试。

捕捉回归

基线图像并没有告诉我太多,除了它们已经捕获了页面的正确区域。要查看回归,我必须引入更改并再次运行测试。

我要将页面标题更改为“登录我的网站”并再次运行测试。现在我已经有了基线图像,WebdriverCSS非常聪明,可以将最新图像与基线进行比较。

测试完成后,现在可以使用两个新图像。第一个位于'baseline'文件夹内,名为'login form.title.regression.png',并显示新捕获的屏幕截图。 '.form'图像保持不变,因为两次测试运行之间没有发生任何变化。

第二个图像('login form.title.diff.png')位于'failures'文件夹中,是diff输出。此图像由ImageMagick生成,并突出显示'.baseline'和'.regression'镜头之间的差异。这有助于我们快速掌握图像的哪些部分实际发生了变化。

接受变化

The WebdriverCSS Admin Panel interface, showing the image diffs and a ‘confirm changes’ button, allowing easier updates for baseline images

WebdriverCSS管理面板界面,显示图像差异和“确认更改”按钮,可以更轻松地更新基线图像

如果您是故意进行更改,则需要更新基准。要执行此操作,请通过删除和重命名文件,将旧的“.baseline”图像替换为新的“.regression”图像。为了帮助完成这个过程,WebdriverIO人员创建了一个管理面板界面这真的改善了工作流程。看看这个。

最后的想法

虽然视觉回归测试仍然是前端的新学科,但使用率正在稳步增长。它与Web的视觉特性一起工作,提供了一种相对简单的方法来收集有用的功能回归结果。花时间尝试一下,下次更新代码库时你会更有信心。

凯文兰普

Kevin Lamping是InVision的高级前端工程师。本文最初发表于网络杂志第272期。

喜欢这个?阅读这些!



翻译字数超限