[From] https://www.qcloud.com/community/article/641602001489391648

作者:yangchunwen

首先要解释一下为什么叫浏览器自动化测试,因为本文只关注发布后页面功能的自动化测试,也就是UI层面的自动化。

浏览器测试有别于js代码的单元测试,后者一般是发布前的代码功能逻辑测试,在这方面已经有很多比较成熟的方案,如jasmine mocha Qunit...

为什么要做自动化

个人认为自动化测试的主要出发点有两点:

  • 减少重复的工作。让机器自动帮我们完成需要的交互操作,验证我们的页面功能。

  • 自动监控。通过自动回归我们的页面功能,可以在功能出错的时候提供报警,为我们手动排除问题提供参考。

开胃菜

说到浏览器自动化测试,不得不介绍大名鼎鼎的phantomjscasperjs。phantomjs可以理解为一个无界面的浏览器,可以通过流水线式的代码来驱动其页面的浏览行为,而后者是前者在易用性API上的一些封装。

这里演示下使用casperjs截取百度首页

关于这两个东西的安装,有兴趣体验的建议去看官方文档,其实很简单,这里不一一赘述。

首先创建一个js文件baidu.js:

var casper = require('casper').create();
casper.start();
casper.thenOpen('http://www.baidu.com/', function () {
casper.captureSelector('baidu.png', 'html');
});
casper.run();

以上代码主要做了三件事:

  1. 创建一个casperjs实例require('casper').create(),可以理解为一个浏览器进程

  2. 打开一个页面casper.thenOpen(...)

  3. 截取页面图像casper.captureSelector

在命令行运行

casperjs baidu.js

看看此脚本生成的图片结果

等等!为什么这个图只有400X300的大小?

原因是我创建了一个浏览器进程去加载页面,但是没有指明用什么浏览器去加载。所以在创建casper实例的时候,可以指定浏览器的窗口大小,甚至我们可以通过指定userAgent的方式冒充手机端的浏览器。例如我们将其指定为iPhone5的safari,并设置窗口大小:

var casper = require('casper').create({
pageSettings: { // 冒充浏览器
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53'
}, // 浏览器窗口大小
viewportSize: {
width: 320,
height: 568
}
});

再次运行后我们的是这样,是不是手机浏览时的样子了?

简单应用

以上的例子,可以知道了怎么使用一个无界面的浏览器去加载页面,并获得页面的界面截图。

我们可以不打开浏览器,一行命令就可以知道页面长啥样了,所以每次我们只要运行这个casperjs脚本,通过截图就能看到我们页面是不是正常的。

但是,通过肉眼去判断,肯定是有违“自动化”的初衷的,所以必须要借助工具来帮我们分析。

最简单直观的办法就是“像素对比”,也就是把两次或多次的截图,逐一对比每一像素或一定范围区域,这样就能产出图片的差别了,如下图:

实际应用中,可以指定一个图片作为基准图,每一次我们截取的页面图与之对比,如果不一样,就可以说明线上的页面出现了异常。

像素对比这样的工具已经比较成熟,这里介绍一个与前端开发非常亲近的方案:Resemble.js

为什么说它和前端亲近,因为它使用的是canvas。我们知道,每一个图片的每一像素,都可以通过RBGA(red,blue,green,alpha)三个值来确定:

Resemble.js的主要原理就是把我们需要对比的图片绘制到canvas中,读取需要对比的像素点(或区域)的image data,从而确定图片的差异。

为了与phantomjs/casperjs更好的结合,Resemble.js作者同时做了基于Resemble.js的封装phantomcss

phantomcss使用了简单的API来做图片对比:

phantomcss.screenshot( "#CSS .selector1", screenshotName1);
phantomcss.screenshot( "#CSS .selector2", screenshotName2);
phantomcss.compareFiles(screenshotName1, screenshotName2);

假如对比的图片有不一致的地方,会生成一张对比图,同时有差异的地方会用显眼的颜色标出,类似这样:

注意

页面截图对比出现不一致,并不能证明我们的页面就出现了异常,例如广告位等,这些变化频繁的区域,每一次对比都有可能出现差异,所以对广告位或其他经常变化的位置不宜所差异对比。
实际应用中,对整个页面进行截图对比是不推荐的,这样的方式过于简单粗暴,我们更应该对页面的各个区域进行细分对比,做细粒度的监控。

cookie

既然是浏览器测试,不能没有cookie的参与,casperjs没有对cookie的操作作封装,可以使用phantomjs直接“种”cookie:

phantom.addCookie({
name: 'cookie',
value: 'value',
domain: '.xx.com',
path: '/',
secure: false,
httponly: false,
expires: Date.now() + (1000 * 60 * 60 * 24 * 5)
});

在前面的开胃菜中,我们访问到的页面都是没有登录态的,这里通过手动植入百度帐号登录态的cookie值来实现登录访问。

在PC端chrome中打开百度首页,并用你的帐号登录,在开发者工具中复制百度帐号关键cookie BDUSS的值

并hard code到你的casperjs脚本中:

phantom.addCookie({
name: 'BDUSS',
value: '你复制的cookie值',
domain: '.baidu.com',
path: '/',
secure: false,
httponly: false,
expires: Date.now() + (1000 * 60 * 60 * 24 * 5)
});

完整代码看这里
运行之后我们再看一下结果

Done!右上角已经有用户名,说明此时我们已经登录了!

交互

简单的截图+对比还远远达不到我们的测试要求,对于自动化原则来说,为我们实现自动化的页面交互才是王道,别急,这就来。

前面介绍了手动种植cookie的方式实现登录,下面看下怎么实现手机端百度的登录过程。

先预览下整个脚本login.js的代码,下面解释一下整个过程:

1. 创建实例。与开胃菜中的配置基本一致,这里为了更快,实例化的配置选择了不加载图片
loadImages: false
2. 加载页面
3. 截取无登录态的页面:
casper.captureSelector('1.png', 'html');

这一步会得到图片1.png,并且右上角是没有用户名的(未登录):

4. 读取当前的所有cookie并输出
var cookies = phantom.cookies;
for (var i = 0, len = cookies.length; i < len; i++) {
console.log(cookies[i].name + ': ' + cookies[i].value);
}

这一步输出到命令行的结果:

可以看到,当前的cookie中还没有百度账号的关键cookie BDUSS。

5. 点击登录按钮
casper.mouse.click('#login');

casperjs(phantomjs)支持了非常丰富的可以支持复杂交互的鼠标事件:

  • click
  • doubleclick
  • rightclick
  • down
  • up
  • move

鼠标事件支持指定操作目标的CSS3路径

6. 点击登录后,会跳转到一个填写用户名和密码的登录页,这里为了方便,强行等待3秒确保登录页加载完
casper.wait(3000);
7. 截取登录页界面
casper.captureSelector('2.png', 'html');
8. 填写表单
casper.evaluate(function () {
document.querySelector('[name=username]').value = '***';
document.querySelector('[name=password]').value = '***';
});

这里使用了一个非常有用的方法evaluate。

9. 截取填写登录表单后的样子
10. 点击登录按钮
11. 等待跳转回首页
12. 截取登录后的首页界面
13. 逐一读取cookie并显示到命令行中

最后,运行测试脚本casperjs login.js能得到4张截图,分别记录了整个登录交互过程中关键步骤的交互效果:

对比图1和图4,区别在于图4右上角的用户名:

同时,在命令行中最后还读取到了登录后的BDUSS cookie值:

再来点猛料

  • iframe里的操作

phantomjs(casperjs)不仅可以在当前页面操作,还可以把当前context切换到iframe里进行操作,这点给嵌入iframe的页面测试带来了很多方便。

  • 操作区域

phantomjs(casperjs)支持使用CSS3选择器及XPath的方式对我们需要操作的目标进行操作(点击、截图等),还可以通过指定区域边界的来操作,例如可以指定x/y坐标/width/height来进行点击或截图等:

casper.capture('capture.png', {
x: 200,
y: 300,
width: 200,
height: 300
});

交互的一些局限

现实世界的web里,有些交互功能不是机械的操作,有时候出于安全或其他因素考虑,页面会做一些限制,要求我们的交互需要根据一些动态输出,这种功能是很难做到完全自动化的,例如,上面的百度登录功能,有时候会出现验证码的情况:

这时候就很难借助机器来帮我们做登录了,所以在前面我要介绍通过手动植入cookie的方式实现登录。

单元测试

通过前面的介绍,使用phantomjs(casperjs)已经能实现很多自动化的功能,在此基础上,实现单元测试就很简单了。

casperjs提供了相对比较完善的单元测试API

单元测试中,每一个testsuite都被包装在一个闭包中:

casper.test.begin('your testsuite', 0, function (test) {
// 单元测试代码
});

例如下面是一个测试百度页面title及log位置是否正确的一组测试用例:

casper.test.begin('test demo', 0, function (test) {

    casper.start();

    casper.thenOpen('http://www.baidu.com/', function () {

        // 测试页面title是否正确
casper.test.assertTitle('百度一下', 'page title'); // 测试logo的位置信息 // 获取x/y/width/height
var layout = casper.getElementBounds('#logo');
layout = JSON.stringify(layout); // 验证是否符合
casper.test.assertEquals(layout, '{"height":87,"left":0,"top":53,"width":320}', 'logo\'s boundary'); }); casper.run(function () {
casper.test.done();
}); });

完整代码test.js在这里

运行casperjs test test.js

可以在命令行中看到以下输出:

两个case都已pass!

与前面的截图肉眼查看的方式相比,单元测试为我们提供了更加简洁的测试结果。

另外,casperjs的test模块还可以在测试后产出XML结果,例如上面那个例子的结果如下:

<?xml version="1.0" encoding="UTF-8" ?>
<testsuites time="2.228">
<testsuite name="test demo" tests="2" failures="0" errors="0" time="2.228"
timestamp="2015-08-31T13:30:12.462Z" package="test">
<testcase name="page title" classname="test" time="2.223">
</testcase>
<testcase name="logo's boundary" classname="test" time="0.005">
</testcase>
<system-out>
</system-out>
</testsuite>
</testsuites>

利用这个XML结果,与报警等系统结合,可以实现各种强大的自动化功能。

问题

  1. 浏览器兼容。
    说到底,phantomjs(casperjs)提供的还是一个无界面的webkit内核浏览器,所以无法覆盖IE浏览器。目前Gecko内核的无界面浏览器已经有解决方案SlimerJS,并且支持与phantomjs一模一样的API。

  2. 设备兼容。
    在各种手机等终端设备良莠不齐的情况下,服务端的无界面浏览器在这点上更难以做到模拟所有的软硬件环境。

原文链接:http://ivweb.io/topic/55e46d8d771670e207a16bdc

[转] 浏览器自动化测试初探:使用 phantomjs 与 casperjs的更多相关文章

  1. 浏览器自动化测试初探 - 使用phantomjs与casperjs

    收录待用,修改转载已取得腾讯云授权 作者:yangchunwen 首先要解释一下为什么叫浏览器自动化测试,因为本文只关注发布后页面功能的自动化测试,也就是UI层面的自动化. 浏览器测试有别于js代码的 ...

  2. PhantomJS、CasperJS安装配置图文详解

    目前网站主流的加载方式: 一种是同步加载:另一种是异步加载,也即我们常说的用ajax.对于同步加载的网站,普通的爬虫程序轻松就能搞定.但是对于那种异步请求数据的网站,通常使用selenium+Phan ...

  3. PhantomJS与CasperJS在Windows下的安装与使用

    按照网上的教程来呢,一定是不好使的,这是常理. 所以必须要告诉你怎么使用Phantomjs…… 这么用! 1.下载Phantomjs的压缩包并解压缩: 2.在bin目录(包含phantomjs.exe ...

  4. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)

    最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题 ...

  5. 前端端对端测试:基于PhantomJS的CasperJS

    简介 Casperjs是一个基于PhantomJS和SlimerJS的前端端对端测试框架,当然你也可以使用它完成网络爬虫功能,它的特点的通过简单的脚本模拟浏览器行为, 主要有casper.tester ...

  6. Selenium浏览器自动化测试工具

    目录 Selenium浏览器自动化测试工具 Selenium模块在爬虫中的使用 Python简单使用Selenium Selenium的基本操作 Selenium爬取动态加载的数据 Selenium动 ...

  7. Python3+unitest自动化测试初探(中篇)

    目录 6.生成测试报告 7.编写邮件发送工具 8.发送邮件 发布 0 86 编辑 删除 Python3+unitest自动化测试初探(中篇)(2019-04-18 01:41) 发布 3 245 编辑 ...

  8. Python3+unitest自动化测试初探(下篇)

    目录 9.用例结果校验 10.跳过用例 11.Test Discovery 12.加载用例 unittest官方文档 本篇随笔承接: Python3+unitest自动化测试初探(中篇) Python ...

  9. 第三百三十七节,web爬虫讲解2—PhantomJS虚拟浏览器+selenium模块操作PhantomJS

    第三百三十七节,web爬虫讲解2—PhantomJS虚拟浏览器+selenium模块操作PhantomJS PhantomJS虚拟浏览器 phantomjs 是一个基于js的webkit内核无头浏览器 ...

随机推荐

  1. c语言练习 二维数组 年平均降水量 月平均降水量

    #define YEARS 5#define MONTHES 12 int main(void) { const float rain[YEARS][MONTHES] = { {4.3,4.3,4.3 ...

  2. export default {} 和new Vue()区别

     1.export default 的用法:相当于提供一个接口给外界,让其他文件通过 import 来引入使用. 而对于export default 和export的区别:  在JavaScript ...

  3. 4.std::string中库函数的使用。

    为了美观,我们把输入和输出设计成如下: #include <iostream> #include <string> int main() { std::string name; ...

  4. Load-time relocation of shared libraries

    E原文地址:http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries/ This article ...

  5. Hadoop安装所遇问题及解决方法

    1.错误:java.io.IOException: File /hadoop/hadooptmp/mapred/system/jobtracker.info could only be replica ...

  6. QGIS编译教程

    注意更新时间:Thursday November 02, 2017 1. Introduction 简介 This document is the original installation guid ...

  7. 【Head First Java 读书笔记】(六)认识Java API

    第五章 使用Java函数库 ArrayList add(Object elem) remove(int index) remove(Object elem) contains(Object elem) ...

  8. APP压力稳定性测试

    转自:https://www.cnblogs.com/nuonuozhou/p/8643735.html 1.android系统自带monkey程序,模拟用户触摸屏幕,滑动track ball,按键等 ...

  9. GitHub小技巧-定义项目语言

    GitHub是根据项目里文件数目最多的文件类型,识别项目类型.后端项目难免会包含前端的资源,有时候就会被标记成前端语言,因为项目里 css 等文件比较多, 被误识别成css项目. GitHub不提供指 ...

  10. 函数返回值string与返回值bool区别------c++程序设计原理与实践(进阶篇)

    为什么find_from_addr()和find_subject()如此不同?比如,find_from_addr()返回bool值,而find_subject()返回string.原因在于我们想说明: ...