If you’ve done any serious development in your career you’ve likely reached the point when you realized the importance of automated testing during development. Depending on your experience, this realization might hit you in one big burst or it may gently come to you over time, but it will eventually become second nature. Automatic testing comes in many forms, from unit testing, when you test isolated pieces of code, to integration and functional testing, when you test how different parts of your system behave together. This article is not about an overview on automatic testing in general. It is about a particular and a relatively new niche referred to as visual regression testing.
如果您在职业生涯中进行了认真的开发,那么您可能已经意识到开发过程中自动测试的重要性。 根据您的经验,这种认识可能会突然袭击您,或者随着时间的流逝它会慢慢出现,但是最终将成为第二天性。 自动测试以多种形式出现,从单元测试到测试孤立的代码段,再到集成和功能测试,再到测试系统不同部分的行为。 本文一般不涉及自动测试的概述。 它是关于特定且相对较新的细分市场,称为视觉回归测试 。
Visual regression testing takes an alternative approach to testing web pages. Instead of just making sure that some element or a text value is present in the DOM, the test actually opens the page and checks if this specific block looks exactly like you want it to. Just to make sure that you picked up the difference, let me give you an example. Imagine, that you want your website to greet your visitors with a friendly message:
视觉回归测试采用另一种方法来测试网页。 测试实际上不只是确保DOM中存在某些元素或文本值,而是实际上打开页面并检查此特定块是否看起来完全像您想要的那样 。 为了确保您了解其中的差异,让我举一个例子。 想象一下,您希望您的网站以友好的信息向访客打招呼:
<div>Hello, %username%!</div>
To make sure it works, you can (and should) unit test the piece of code that produces the message, checking that it inserts the correct name. You can also write a functional test using Selenium or Protractor to see if the element is actually present on the page with the correct text. But this is not enough. We want to test not just that the text is generated correctly or appears in the DOM but to make sure that the whole element looks correct, i.e., making sure that the element is not hidden by display: none
or that someone hasn’t accidentally overridden the color of the text. There are a number of tools to do that, but today we will be looking at one option in particular — PhantomCSS.
为确保其正常工作,您可以(并且应该)对生成消息的代码进行单元测试,并检查其是否插入了正确的名称。 您也可以使用Selenium或Protractor编写功能测试,以查看元素是否实际以正确的文本显示在页面上。 但这还不够。 我们不仅要测试文本是否正确生成或出现在DOM中,还要确保整个元素看起来正确 ,即确保该元素未被display: none
隐藏display: none
或没有被意外覆盖文字的颜色。 有许多工具可以做到这一点,但是今天我们将特别关注一个选项-PhantomCSS 。
什么是PhantomCSS? (What is PhantomCSS?)
PhantomCSS is a Node.js tool to perform visual regression testing. It is open source and developed by the guys at Huddle. PhantomCSS allows you to run a headless browser, open a page and take a screenshot of the whole page or a particular element on the page. This screenshot will be stored as a baseline image for future reference. Whenever you change anything on the website, you can run PhantomCSS again. It will take another screenshot and compare it to the original image. If there are no differences found, the test will pass. If, however, the screenshots don’t match, the test will fail and a new image showing the difference will be created for you to review. This approach makes this tool perfect for testing changes in CSS.
PhantomCSS是执行视觉回归测试的Node.js工具。 它是开源的,由Huddle的开发人员开发。 PhantomCSS允许您运行无头浏览器,打开页面并截取整个页面或页面上特定元素的屏幕截图。 此屏幕快照将存储为基线图像,以备将来参考。 每当您在网站上进行任何更改时,都可以再次运行PhantomCSS。 它将需要另一个屏幕截图,并将其与原始图像进行比较。 如果没有发现差异,则测试将通过。 但是,如果屏幕截图不匹配,则测试将失败,并将创建显示差异的新图像供您查看。 这种方法使该工具非常适合测试CSS中的更改。
PhantomCSS is built on top of several key components:
PhantomCSS建立在几个关键组件之上:
CasperJS – a tool for interacting with a PhantomCSS or SlimerJS browser. It allows you to open a page and perform user interactions, such as clicking on buttons or inputting values. Additionally, CasperJS provides its own testing framework and the ability to capture screenshots of a page.
CasperJS –与PhantomCSS或SlimerJS浏览器进行交互的工具。 它允许您打开页面并执行用户交互,例如单击按钮或输入值。 此外,CasperJS提供了自己的测试框架,并能够捕获页面的屏幕截图。
PhantomJS 2 or SlimerJS – two different headless browsers, either of which can be used with PhantomCSS. A headless browser is just like a normal browser without a user interface.
PhantomJS 2或SlimerJS –两种不同的无头浏览器,两种浏览器均可与PhantomCSS一起使用。 无头浏览器就像没有用户界面的普通浏览器一样。
Resemble.js – a library for comparing images.
Resemble.js –用于比较图像的库。
PhantomCSS can be used together with both PhantomJS and SlimerJS, but in this article, we’ll be using PhantomJS.
PhantomCSS可以与PhantomJS和SlimerJS一起使用,但是在本文中,我们将使用PhantomJS。
让我们一起旋转 (Let’s Take It for a Spin)
Let’s set up a tiny test project to see how we can use this tool in practice. For that, we’ll need a web page to test and a simple Node.js web server for CasperJS to be able to open the page.
让我们建立一个很小的测试项目,看看如何在实践中使用此工具。 为此,我们需要一个网页来测试,以及一个简单的Node.js Web服务器,CasperJS才能打开该页面。
设置测试项目 (Setting up a Test Project)
Create an index.html
file with some sample content:
创建带有一些示例内容的index.html
文件:
<!doctype html>
<html>
<head>
<style>
.tag {
color: #fff;
font-size: 30px;
border-radius: 10px;
padding: 10px;
margin: 10px;
width: 500px;
}
.tag-first {
background: lightcoral;
}
.tag-second {
background: lightskyblue;
}
</style>
</head>
<body>
<div class="tag tag-first">The moving finger writes, and having written moves on.</div>
<div class="tag tag-second">Nor all thy piety nor all thy wit, can cancel half a line of it.</div>
</body>
</html>
To install the web server, initialize an npm project and install the http-server
package.
要安装Web服务器,请初始化一个npm项目并安装http-server
软件包。
npm init
npm install http-server --save-dev
To run the server, let’s define a simple npm script. Just add the following scripts
section to package.json
要运行服务器,让我们定义一个简单的npm脚本。 只需将以下scripts
部分添加到package.json
"scripts": {
"start": "http-server"
},
Now you can run npm start
from the project folder and the index page will be accessible on the default address http://127.0.0.1:8080
. Start the server and leave it running for now. We’ll need it in a while.
现在,您可以从项目文件夹运行npm start
,并且可以在默认地址http://127.0.0.1:8080
上访问索引页面。 启动服务器,使其暂时运行。 我们会在一段时间内使用它。
安装PhantomCSS (Installing PhantomCSS)
Installing PhantomCSS is easy, all you need to do is add a few dependencies to your project:
安装PhantomCSS很容易,您需要做的就是在项目中添加一些依赖项:
npm install phantomcss casperjs phantomjs-prebuilt --save-dev
创建测试套件 (Creating a Test Suite)
Now we have everything we need to set up the first test suite. PhantomCSS test suites are created in the form of Node.js scripts where you open the required page of your website, take screenshots and compare them to the images from the previous run. We start with a simple test case based on the demo from PhantomCSS itself.
现在,我们拥有设置第一个测试套件所需的一切。 PhantomCSS测试套件以Node.js脚本的形式创建,您可以在其中打开网站的所需页面,截取屏幕截图并将其与上次运行的图像进行比较。 我们从基于PhantomCSS本身的演示的简单测试案例开始。
var phantomcss = require('phantomcss');
// start a casper test
casper.test.begin('Tags', function(test) {
phantomcss.init({
rebase: casper.cli.get('rebase')
});
// open page
casper.start('http://127.0.0.1:8080/');
// set your preferred view port size
casper.viewport(1024, 768);
casper.then(function() {
// take the screenshot of the whole body element and save it under "body.png". The first parameter is actually a CSS selector
phantomcss.screenshot('body', 'body');
});
casper.then(function now_check_the_screenshots() {
// compare screenshots
phantomcss.compareAll();
});
// run tests
casper.run(function() {
console.log('\nTHE END.');
casper.test.done();
});
});
The test will open http://127.0.0.1:8080/
, take a screenshot of the body
element and save it under screenshots/body.png
.
测试将打开http://127.0.0.1:8080/
,对body
元素进行screenshots/body.png
并保存在screenshots/body.png
。
Once we have the test itself in place, all that’s left is to define a script to run the test. Let’s add the following script to package.json
next to start
:
一旦完成测试本身,剩下的就是定义一个脚本来运行测试。 让我们在start
旁边的package.json
添加以下脚本:
"test": "casperjs test test.js"
You can now run it by executing the following command:
现在,您可以通过执行以下命令来运行它:
npm test
The output you will see should look something like this:
您将看到的输出应如下所示:
Test file: test.js
# Tags
PASS Tags (NaN test)
New screenshot at ./screenshots/body_0.png
Must be your first time?
Some screenshots have been generated in the directory ./screenshots
This is your 'baseline', check the images manually. If they're wrong, delete the images.
The next time you run these tests, new screenshots will be taken. These screenshots will be compared to the original.
If they are different, PhantomCSS will report a failure.
THE END.
WARN Looks like you didn't run any tests.
npm ERR! Test failed. See above for more details.
Since you’ve run the test for the first time, it will just create a new baseline screenshot and won’t perform any comparison. Go ahead and peek inside the screenshots
folder. You should see an image like this one:
由于您是第一次运行测试,因此它只会创建一个新的基准屏幕截图,并且不会执行任何比较。 继续并浏览screenshots
文件夹。 您应该看到这样的图像:
This is the golden standard of how your website is supposed to look and future executions of the test will compare their results to this image.
这是网站外观的黄金标准,以后的测试执行会将其结果与此图像进行比较。
引入回归 (Introducing a Regression)
If you run the same test command again it will report that all tests have passed successfully:
如果再次运行相同的测试命令,它将报告所有测试已成功通过:
Test file: test.js
# Tags
PASS Tags (NaN test)
PASS No changes found for screenshot ./screenshots/body_0.png
PhantomCSS found 1 tests, None of them failed. Which is good right?
If you want to make them fail, change some CSS.
THE END.
PASS 1 test executed in 0.827s, 1 passed, 0 failed, 0 dubious, 0 skipped.
This is to be expected since we haven’t changed anything on the website. Let’s break something and re-run the tests again. Try changing some styles in index.html
, for example, decrease the size of the blocks to 400px. Now let’s run the test again and see what happens:
这是可以预料的,因为我们尚未更改网站上的任何内容。 让我们破坏一些东西,然后重新运行测试。 尝试更改index.html
某些样式,例如,将块的大小减小到400px。 现在,让我们再次运行测试,看看会发生什么:
Test file: test.js
# Tags
PASS Tags (NaN test)
Failure! Saved to ./failures/body_0.fail.png
FAIL Visual change found for screenshot ./screenshots/body_0.png (11.41% mismatch)
# type: fail
# file: test.js
# subject: false
PhantomCSS found 1 tests, 1 of them failed.
PhantomCSS has created some images that try to show the difference (in the directory ./failures). Fuchsia colored pixels indicate a difference between the new and old screenshots.
THE END.
FAIL 1 test executed in 1.082s, 0 passed, 1 failed, 0 dubious, 0 skipped.
Details for the 1 failed test:
In test.js
Tags
fail: Visual change found for screenshot ./screenshots/body_0.png (11.41% mismatch)
npm ERR! Test failed. See above for more details.
Several important things have happened here. First, PhantomCSS reported that the tests failed because of a mismatch for screenshot body_0.png
. The mismatch is measured at 11.41%. Second, the difference between the current and the previous version was saved in the failures
folder. If you open it, you will see a screenshot like this one:
这里发生了几件重要的事情。 首先,PhantomCSS报告说,由于屏幕截图body_0.png
不匹配,测试失败。 失配率为11.41%。 其次,当前版本与先前版本之间的差异保存在failures
文件夹中。 如果打开它,您将看到类似以下的屏幕截图:
The screenshot conveniently highlights the areas that have been changed so it’s easy to spot the difference.
屏幕截图方便地突出显示了已更改的区域,因此很容易发现差异。
接受变更 (Accepting the Changes)
Now that the difference has been highlighted, what should we do to accept the change? We should somehow be able to tell the tool that we want to stick with the reduced width of the blocks and accept the current view as the new standard. To do that, you can run the test command with an additional -- --rebase
argument:
既然已经突出显示了差异,那么我们应该怎么做才能接受更改? 我们应该能够以某种方式告诉工具我们要坚持减小块的宽度,并接受当前视图作为新标准。 为此,您可以运行带有附加的-- --rebase
参数的test命令:
npm test -- --rebase
Note the two double dashes. It’s npm’s way of passing a parameter to the underlying command. So the following command will result in casperjs test test.js --rebase
. Now that we’ve accepted the change, the previous baseline image will be replaced with the new one.
请注意两个双破折号。 这是npm将参数传递给基础命令的方式。 因此,以下命令将导致casperjs test test.js --rebase
。 既然我们已经接受了更改,那么以前的基准图像将被替换为新的基准图像。
更进一步 (Taking it Further)
Now that you’ve got the hang of the basics, you can start thinking about integrating this tool into your own workflow. I won’t get into the details of that since it is pretty project specific, but here are some questions to ponder about:
掌握了基础知识之后,就可以开始考虑将此工具集成到您自己的工作流程中了。 由于它是特定于项目的,因此我将不对其进行详细介绍,但以下是一些需要考虑的问题:
- Are you going to run the tests against the real website, or some kind of style guide, where only separate UI elements are present? 您要针对仅显示单独的UI元素的真实网站或某种样式指南进行测试吗?
- Does your site have dynamic content? If yes, then changes in the content will cause the tests to break. To avoid that, you’ll need to set up a separate version of the website with static context to run the tests against it. 您的网站是否包含动态内容? 如果是,则内容更改将导致测试失败。 为避免这种情况,您需要使用静态上下文设置网站的单独版本,以对该网站进行测试。
- Are you going to add the screenshots into your version control? Yes, you should. 您是否要将屏幕截图添加到版本控制中? 是的你应该。
- Are you going to take screenshots of whole pages, or separate elements? 您要拍摄整个页面或单独元素的屏幕截图吗?
Using this tool you can now cover the visual aspects of your website with automated tests. With your unit and functional tests already in place, this new strategy will fill a narrow gap in your testing frontier. Even if you are still new to testing — this is a good place to start!
现在,您可以使用此工具通过自动化测试来覆盖网站的视觉效果。 在已经完成单元测试和功能测试的情况下,这种新策略将填补测试领域中的一个空白。 即使您还不熟悉测试,这也是一个不错的起点!
翻译自: https://www.sitepoint.com/visual-regression-testing-with-phantomcss/