以下是 Garris Shipon 的客座文章。 我们之前已经讨论过 四种 CSS 测试类型。 回归测试是最困难的。 这种测试类型用于测试对 CSS 的更改是否会导致任何意外的视觉问题。 对于响应式设计来说,这更加困难。 Garris 在为大型网站构建新的响应式设计时,构建了一个用于执行此操作的工具。 在这里,他将带您完成整个过程。
本文最初发表于 2014 年 12 月。 现在已在 2016 年 4 月重新编写、更新并重新发布,因为这里介绍的主要工具 BackstopJS 已更新。
视觉回归测试用例
搜索“CSS 回归测试”,一个共同的主题变得清晰:破坏 CSS 很容易,测试它很难。
在我的一个大型在线零售商的响应式 CSS 重构项目开始时,情况就是这样。 与当时许多其他网络公司一样,我们正在为一个庞大的电子商务网络应用程序添加响应式行为,该应用程序最初是为 1024px 桌面屏幕设计的。
我意识到这将是一项容易出现回归的任务。 调整多个断点行为意味着我们很可能会有很多难以发现的显示错误。 我需要一种方法让我们的工程师能够在将数百个细微的布局问题提交给我们的 QA 团队之前自动发现错误。
BackstopJS 的应用场景
我想要的解决方案必须与 Web 开发人员配合使用。 也就是说,易于在本地安装,使用熟悉的 Web 开发范式,并提供合理的信心,确保为移动设备制作的选择器更改不会导致桌面布局中难以发现的错误。
当时,没有开箱即用的东西完全符合要求。 这就是创建 BackstopJS 的原因。
BackstopJS 是一个视觉回归测试应用程序,它将 CasperJS、PhantomJS 和 ResembleJS 捆绑在一个易于配置的测试矩阵中,跨越多个应用程序状态(URL)、DOM 元素和屏幕尺寸。
以下是 BackstopJS 安装和初始配置的 15 分钟演练。
视觉回归测试教程
本说明将基于一个简单的演示项目(在此下载 ZIP 文件)。 它直接取自 Bootstrap 的 示例页面。
扩展简单的演示
解压缩项目下载。 我们将在该示例项目中安装测试框架。

如果您在 Web 浏览器中打开myCoolProject/index.html
,您将看到以下内容…请记住,它是响应式的。 因此,请确保调整浏览器窗口大小,使其变小,以查看最窄的布局!

使用 NPM 安装 BackstopJS
现在,转到您的项目根目录(/myCoolProject/
)并运行
$ cd ~/path-to-myProjects/myCoolProject
$ npm install backstopjs
您的目录现在应该如下所示

安装完成! 现在让我们进行一些基本的测试…
生成 BackstopJS 配置模板
从这里开始,基本的配置过程很简单。 为了帮助您,BackstopJS 可以生成一个配置文件,您可以根据自己的项目对其进行修改。 从myCoolProject/node_modules/backstopjs/
目录运行
$ cd ~/path-to-myProjects/myCoolProject/node_modules/backstopjs/
$ npm run genConfig
这会将文件添加到您的项目根目录:用于 BackstopJS 屏幕截图的文件夹、backstop_data
和一个生成的基本配置文件 backstop.json
。

配置文件是您指定测试规则的地方。 让我们看一下该文件。
{
"viewports": [
{
"name": "phone",
"width": 320,
"height": 480
}, {
"name": "tablet_v",
"width": 568,
"height": 1024
}, {
"name": "tablet_h",
"width": 1024,
"height": 768
}
],
"scenarios": [
{
"label": "My Homepage",
"url": "https://bootstrap.ac.cn",
"hideSelectors": [],
"removeSelectors": [
"#carbonads-container"
],
"selectors": [
"header",
"main",
"body .bs-docs-featurette:nth-of-type(1)",
"body .bs-docs-featurette:nth-of-type(2)",
"footer",
"body"
],
"readyEvent": null,
"delay": 500,
"onReadyScript": null,
"onBeforeScript": null
}
],
"paths": {
"bitmaps_reference": "../../backstop_data/bitmaps_reference",
"bitmaps_test": "../../backstop_data/bitmaps_test",
"compare_data": "../../backstop_data/bitmaps_test/compare.json",
"casper_scripts": "../../backstop_data/casper_scripts"
},
"engine": "phantomjs",
"report": ["browser", "CLI"],
"cliExitOnFail": false,
"debug": false,
"port": 3001
}
在此配置中,您可以看到三个viewports
对象。 一个用于手机、平板电脑纵向和平板电脑横向,每个对象都有名称和尺寸属性。 您可以根据需要添加任意数量的viewports
对象。 BackstopJS 至少需要一个。
然后我们有scenarios
,其中包含 BackstopJS 将测试的 URL 和元素选择器。 将每个场景对象视为特定静态页面或全局应用程序状态的测试非常有用。 根据需要添加任意数量的scenarios
。 BackstopJS 至少需要一个。
每个场景内都有一个选择器列表。 选择器接受标准 CSS 表示法。 对于您指定的每个选择器,BackstopJS 将获取屏幕截图并测试您的布局的该区域。 您的选择器区域可以小到一个button
,也可以大到您页面的body
——查看文档以详细了解如何在动态 Web 应用程序中使用此功能。
修改配置模板
对于我们的演示,请进行以下更改,并替换myCoolProject/backstop.json
中的scenarios
节点。
"scenarios": [
{
"label": "My Local Test",
"url": "../../index.html",
"hideSelectors": [],
"removeSelectors": [
],
"selectors": [
"nav",
".jumbotron",
"body .col-md-4:nth-of-type(1)",
"body .col-md-4:nth-of-type(2)",
"body .col-md-4:nth-of-type(3)",
"footer"
],
"readyEvent": null,
"delay": 0,
"onReadyScript": null,
"onBeforeScript": null
}
],
生成参考屏幕截图
从myCoolProject/node_modules/backstopjs/
目录运行…
$ npm run reference
此任务将在/myCoolProject/backstop_data/bitmaps_reference/
中创建一个(或更新现有的)代表所有指定选择器在每个断点处的屏幕截图。 进程完成后,查看/myCoolProject/backstop_data/bitmaps_reference/
中的内容。

到目前为止一切顺利。 我们已经设置了参考集。 现在让我们运行一个测试!
运行我们的第一个测试
我们即将运行第一个测试。但请记住,我们还没有更改 CSS 中的任何内容,因此我们的测试应该通过!
从myCoolProject/node_modules/backstopjs/
目录运行
$ npm run test
此任务将在/myCoolProject/backstop_data/bitmaps_test/<timestamp>
中创建一个新的带时间戳的测试图像目录。
生成测试图像后,BackstopJS 将打开您的 Web 浏览器并显示一个报告,将最新的测试位图与当前参考图像进行比较。 将检测并显示重要差异(如果有)。

在这种情况下,由于我们没有对测试页面进行任何更改,因此 BackstopJS 应该显示所有测试都已通过。 现在,让我们尝试更改 CSS 并看看会发生什么。
更新索引文件并运行第二个测试
如果您在 Web 浏览器中打开(未更改的)`myCoolProject/index.html`,您将看到以下内容。请注意文本周围的边距

让我们把它搞砸!打开`myCoolProject/index.html`,并在结束的`</head>`标签之前插入以下代码
<style>
.jumbotron {
padding: 0px;
}
</style>
以下是页面现在的外观

这正是 Web 开发过程中经常发生的事情。一些未作用域的代码会进入并破坏您的布局,以至于您可能不会注意到 :-(
现在,从`myCoolProject/node_modules/backstopjs/`目录运行
$ npm run test
我们的测试应该再次运行,并且应该找到错误。向下滚动报告以查看我们刚刚创建的问题的视觉差异……

我们的视觉差异包含参考捕获、最新测试捕获和视觉差异文件。

找到了回归!
这是一个非常简单的例子。在现实生活中,设计师和工程师可能会发现自己正在处理非常庞大或复杂的 CSS 项目。在这种情况下,这种系统会真正提高我们工作质量和一致性。通过自动化重复的视觉任务,我们可以自信地追求更有创意的任务。
关于工作流程
有很多方法可以将这种测试集成到您的工作流程中。您可以在每次构建时触发测试,或者您也可以手动运行测试(在您工作时或在推送到下一阶段之前)。如果您愿意,您甚至可以将 BackstopJS 集成到您的 CI 管道中。所有这些主题都超出了本文的范围。查看文档以了解更多信息。
下一步
自从 2014 年首次发布以来,BackstopJS 已发展壮大。社区开发了许多新功能
- SPA 测试支持 – 使用 Casper 脚本和显式 Web 应用程序触发器来确保在 Web 应用程序的正确时间捕获屏幕截图(例如,在 API 响应后、在 CSS 动画完成之后或等待任何其他可观察的异步进程)。
- 模拟用户交互 – 在您的场景中使用 Casper 脚本模拟与屏幕上组件的交互。
- CI 管道集成 – BackstopJS CLI 功能使高级用户能够将视觉回归测试作为其持续集成过程的一部分。
- 活动配置文件 – 允许在您的配置文件中使用活动(节点模块)逻辑,您可以使用它根据环境或其他条件更改测试行为,指向不同的配置文件以将您的 BackstopJS 实例用作多个环境、垂直领域、配置文件、项目或任何其他事物的集中测试服务器。
更多关于 BackstopJS 的信息
- BackstopJS.org
- 查找文档、提交错误、获取故障排除帮助、了解高级功能并在 GitHub 上贡献!
我总是对 Web 开发要学习的东西感到惊讶。然而,这仍然令人兴奋。
太棒了,等不及要试试了。我真的很喜欢 Web 的发展方向。
试过它,我爱上了它。
期待更多浏览器引擎支持。
我在安装时遇到一个问题。
–> sudo npm install phantomjs
我不得不全局安装它“-g”
–> sudo npm install -g phantomjs
@Kenneth 可以看看 Gemini (https://github.com/bem/gemini) 了解更广泛的支持
感谢兄弟帮助我
酷故事,兄弟。可惜了那个 document.ready() 部分,这是这里的一个障碍。期待明年的更新!
我也是。我真的很兴奋,直到我读到最后一段。不过,很酷的工具。期待未来的改进。
是的,我知道——这实际上是我大多数项目中非常大的障碍,而且我构建了这个工具!我计划将其作为下一个更新添加。类似于控制台或窗口上的侦听器,可以使用……
如果 consoleOrWindowReadyEvent 为真,BackstopJS 将等待运行测试。因此,您的应用程序将在视图加载完毕后决定何时发出(例如“everythingIsReady”)在控制台或窗口节点上——然后将运行快照。
这里任何评论或建议都将非常棒。当然,这里任何贡献都将非常出色。;)
您对 Gemini 怎么看?
目前最好的 css 回归工具 :)
http://sourcejs.com/ 计划添加对 gemini 的支持。
您对 https://github.com/winsonwq/viff 怎么看?
我不明白为什么这么多回归测试框架要求用户在其机器上全局安装 Phantom 和 Casper 等模块。我觉得这要求太多,尤其是如果您想在 CI 环境中集成这样的解决方案。我创建了以下插件,它们松散地基于 PhantomCSS,可以选择使用 ResembleJS 进行图像比较。CLI 使用 Phantom 和 Casper 可执行文件而不是全局安装
https://npmjs.net.cn/package/resemble-cli
https://npmjs.net.cn/package/grunt-resemble-cli
您的框架比这些好得多(因为它们不截取组件的屏幕截图,只截取完整页面的屏幕截图),但这还允许使用 GraphicsMagick 进行图像比较(必须全局安装)。如果有一个模块我希望用户全局安装,那应该是 GM 而不是 Phantom 或 Casper,因为我发现 Resemble 中的图像比较非常慢,而在 GM 中几乎是即时的。
另外,为什么不也将其发布到 NPM,并为用户节省在 Bower 存储库中执行 cd 和 npm install 的步骤呢?
终于!我一直在梦想着这样的东西,但太懒了,没有自己去研究。现在,当它几乎像在盘子里一样被送来时,我一定会好好利用它。谢谢!
视觉回归测试对大型网站,尤其是在大型团队中非常有用。我在 http://sonniesedge.co.uk/2014-10-17/visual-regression-testing.html 中记录了我实施它的经验
Charlie,我真的很喜欢你文章中的流程细节和想法!我也想知道如何将它与抓取样式指南的组件结合起来,以及使用 uncss 的工作流程。我对 Grunt/Gulp 还比较陌生,所以希望我不会太深入。Chris,你一如既往地棒!
视觉回归测试,如果是在像 WordPress 这样的博客上进行测试,该怎么做?这里是否有关于在 WordPress 上讨论视觉测试的教程?
谢谢
我发现基于图像的测试的问题是,它不适用于动态内容。在一个最近的项目中,该项目由多个单页应用程序组成,我们使用了 Galen 框架 来实现混合方法:使用图像比较来比较静态组件和 UI 度量,使用 Selenium 来测试内容和检查 CSS 规则。Galen 同时处理这两者。它确实需要一些配置,但它也与 Browserstack/SauceLabs 兼容,以帮助避免处理 VM,并在真实设备上提供测试。
就完整的测试覆盖率而言,我还没有找到任何可比的东西。
我绝不是像你这样的高手。但对于“意外的视觉问题”,我过去在更改方面做过一些测试,并在不同的浏览器等中尝试过 - 只是在将更改应用到网站后不久就收到了电子邮件,用户告诉我他们在与我已经“令人满意地”测试过的完全相同的浏览器中遇到了这样的问题。但是,位图引用当然仍然是一个绝妙的想法,可以捕获我可能一开始就没有“看到”的东西!
+1
正在测试的网站通常具有动态内容。这意味着内容可能会发生更改,回归测试将失败。我通过在开发环境中保留一个样式指南部分来解决这个问题。这些是具有每个经过样式化的组件的静态 HTML 页面。除了可测试性之外,它也是 CSS 通常设计良好的一个很好的证明。作为一个画廊,样式指南在选择组件以供重复使用时非常方便。此外,从技术上讲,这使其更接近单元测试。无论是回归还是非回归,这样一来,实际上我们独立地测试了每个组件的样式,并在出现问题时收到通知,无论上下文如何。
以下是操作步骤
http://dsheiko.com/weblog/automated-css-regressive-testing-in-practice/
是否有不依赖 NPM 和 Node 的此工具版本?
目前我对尝试 Node 没有兴趣,将来也没有计划,但它似乎构建了许多很棒的工具。
Gemini 可能是现在最突出的工具。它利用 Selenium 和 PhantomJS,实现跨浏览器回归测试。
https://github.com/gemini-testing/gemini
太棒了!
很棒的文章,感谢分享 Garris Shipon。
干杯!
我尝试使用它,但在运行
‘npm run reference’
我收到以下错误
”’
BackstopJS 配置加载到位置 D:\www\demo\backstop.json
[09:34:41] 使用 gulpfile D:\www\demo\node_modules\backstopjs\gulpfile.js
[09:34:41] 启动 'echo'...
使用 CasperJS 运行:[ 'capture/echoFiles.js' ]
[09:34:41] 'echo' 完成,耗时 16 毫秒
回显文件失败,代码:1
”’
我在安装了 NPM 和 NodeJS 的 Windows 10 上运行它
我遇到与你相同的错误。你找到解决方法了吗?
请在 github 上发布任何问题。谢谢!https://github.com/garris/BackstopJS/issues
干得好,Garris!