本文的目录结构:css
前端自动化测试的方向有:html
单元测试已经有很是完善的工具体系,借用2016 JavaScript 之星的图,经常使用的单元测试框架有:前端
UI回归测试一般采用的方法是像素对比:java
初次运行的时候,会截图并做为baseline,后面再运行的时候,再生成截图,并与baseline比较,生成diff结果。react
像素对比须要注意的事项:git
以下图,很方便的实现了一个百度贴吧自动发帖的功能。github
一般的工具备:chrome devtool,PageSpeed等在线测试网站。chrome
考虑到咱们主题是nek-ui组件库的测试,性能测试的部分,这里不作赘述。npm
咱们的测试对象是NEK-UI组件库,这一部分分析了其余组件库的测试方法并选择了最终的测试方案。编程
RegularUI使用的测试方案是karma + mocha的黄金搭档
这种方式存在的问题:
Ant-design是蚂蚁金服的一套企业级的 UI 设计语言和 React 实现,目前是Github上一个很火的项目:
Ant-design做为一个基于react的组件库,使用的测试框架是一样出自Facebook的Jest。
Ant-design使用的是Jest中称为snapshot testing的测试方案。
Jest的官方文档上介绍到,Jest的Snapshot Testing与典型的snapshot test不一样,不是生成截图并比较图片的差别,而是直接输出React tree 的最终渲染dom结构。
Snnpshot Testing介绍:
再来看看Ant-design中的实际使用:
测试某个组件的时候,就会引入改组件文件夹里demo文件夹下的全部md文件,这个md文件是组件的各类示例,同时也用于ant-design的官方文档。而后,使用enzyme和enzyme-to-json提供的方法通过render->renderToJson->toMatchSnapshot, 第一次运行的时候会输出以下的.snap文件:
这个文件要随着代码一块儿提交到仓库,下次运行测试的时候,就和这个.snap文件作比较。
固然仅仅测试dom结构不变是不够的,ant-design的测试里,还有模拟用户操做的测试。以下两个文件,demo.test.js是上面的snapshot部分,index.test.js是模拟用户操做部分。
Index.test.js里作了什么呢?
在组件上绑定事件方法,而后模拟事件,判断方法是否被调用。
这种方式存在的问题:
分析完了2个组件库的测试方案,那么咱们指望的测试方案应该包含什么呢?
能方便的管理test case。
基于此,咱们最终选择了PhantomFlow。
PhantomFlow是基于决策树(decision tree)的ui test 框架,是对PhantomJS、CasperJS、PhantomCSS的包装。
PhantomFlow假定若是页面正常,那么在相同的操做下,每次页面所展示的应该是同样的。基于这点,使用者只须要定义一系列的操做流程和决策分支,而后利用PhantomCSS进行截图和图像对比。最后将测试结果在一个可视化报表中展示出来。
这里采用倒序的方式先来看一下PhantomFlow生成的测试报告,再介绍具体的使用:
这是PhantomFlow的母公司Huddle在他们实际的业务中使用的报告截图:
同时PhantomFlow也提供了单独查看某一个操做流的功能:
图中的每一条线表明一个用户操做流。绿色的点表示截图对比经过,红色的点表示截图对比失败,灰色的点表示这仅仅是PhantomFlow流程中的一步,并无真正的操做。
黄色的表示是一个操做,可是操做里面并无进行截图。咱们只要关心其中绿色的点和红色的点。
PhantomFlow是基于决策树的,那么什么是决策数呢?不必吧它想的那么神秘,咱们能够认为它就是普通的流程图。
flow (string, callback):初始化一个test suite,回调函数中能够包含step, chance 和 decision。
step (string, callback):一个单独的步骤,回调函数中能够包含PhantomCSS的截图,CasperJs的操做事件和断言
decision (object):定义一个用户的决定,参数是一个对象,key用来描述decision的名称,value是一个function,里面能够包含后续的decision, chance和step
chance (object):功能上同decision同样,只是在语义上区分decision,用来描述不是用户主动的行为。
step对应决策树中的矩形,表示用户具体的某一个操做。decision和chance对应决策树中的菱形,表示用户的选择。
这是用PhantomFlow描述用户喝咖啡的一个场景:
PhantomFlow提供了简单的方法来描述用户的操做流,具体的操做使用回调函数里的CasperJS来完成:
function goToPage() {
casper.thenOpen("http://localhost:9001/test/index.html", function() {
this.echo('PageTitle: ' + this.getTitle());
phantomCSS.turnOffAnimations();
});
}
function injectModule(json) {
casper.evaluate(function(json) {
console.log(JSON.stringify(json));
new NEKUI.UISelect(json).$inject('#module');
}, json);
casper.onConsoleMessage = function(msg) {
console.log(msg);
}
}
function goToModule() {
casper.waitForSelector(
'#module .u-select2',
function success() {
phantomCSS.screenshot('#module .u-select2');
casper.test.pass('Should see the uiselect module' );
},
function timeout() {
casper.test.fail('Should see the uiselect module');
}
)
}
function clickModule() {
casper.click('#module .dropdown_hd');
casper.waitForSelector(
'#module .dropdown_bd',
function success() {
phantomCSS.screenshot('body');
casper.test.pass('Should see the options of module');
},
function timeout() {
casper.test.fail('Should see the options of module');
}
)
}
function selectAnOption(optionIndex) {
casper.click('#module .m-listview li:nth-child(' + (optionIndex+1) + ')');
phantomCSS.screenshot('body');
}复制代码
在npm test后带上以下参数便可
report:打开浏览器,生成测试报告。
debug:输出更多的log信息,强制切换到单线程运行。
earlyexit: 默认为false,设置为true的话,遇到第一个failure就会终止测试。
threads:设置多线程来运行测试,默认为4。
casper.thenOpen(String location[, mixed options]): 用来打开一个地址,当网页加载完成以后,执行一个方法。
casper.waitForSelector(String selector[, Function then, Function onTimeout, Number timeout]):等到DOM里有一个元素匹配选择器,能够传入成功的方法和失败的方法,和等待的毫秒数(默认5000)。
casper.click(String selector, [Number|String X, Number|String Y]):在匹配选择器的第一个元素上执行一次click
casper.mouseEvent(String type, String selector, [Number|String X, Number|String Y]):在匹配选择器的第一个元素上触发鼠标事件。支持的事件有:mouseup、mousedowm、click、dblclick、mousemove、mouseover、moustout、mouseenter、mouseleave and contextmenu
casper.getHTML([String selector, Boolean outer]):获取匹配选择器里的元素的内容。
casper.evaluate(Function fn[, arg1[, arg2[, …]]]):在打开的当前页面环境下执行方法。
casper.test.fail(String message):添加一个fail test。
casper.test.pass(String message):添加一个pass test。
casper.test.assertEquals(mixed testValue, mixed expected[, String message]):断言两个值严格相等。
持续集成(Continuous integration,CI),一种软件工程流程,指工程师将本身对于软件的复本,天天集成数次到主干上。在测试驱动开发(TDD)的作法中,一般还会搭配自动单元测试。
Travis-ci是一款持续集成服务,它可以很好地与Github结合,每当代码更新时自动地触发集成过程。Travis CI
打开Travis CI的官网,用Github帐号登陆。
选择须要打开Travis CI服务的仓库:
开通了服务的仓库,每当有push代码的时候,Travis CI就会为咱们执行相关的操做。这里能够查看运行的进度和结果等。
在Github提交记录里也会显示CI运行的结果。
要告诉Tracvis执行什么,须要在咱们的项目里添加一个.travis.yml文件,其最简单的配置以下:
这里指定了CI运行的语言,语言版本,哪些分支,install执行npm install, script是具体的操做部分,这里让CI执行 npm test。
Travis CI在执行完以后,会将结果邮件通知给用户, 默认规则以下:
By default, email notifications are sent to the committer and the commit author when they are members of the repository,
that is they have
- push or admin permissions for public repositories.
- pull, push or admin permissions for private repositories.
Emails are sent when, on the given branch:
- a build was just broken or still is broken.
- a previously broken build was just fixed.复制代码
关于travis ci的生命周期等更多配置能够查阅这里
一样的使用Github帐号登录:
选择开启服务的仓库:
在项目的package.json文件script里添加一条coverage的命令, 即将istanbul等覆盖率工具生成的lcov文件给coveralls:
在travis.yml文件的after_script中运行npm run coverage,告诉CI服务器执行这条命令:
自动化测试不只能有效的减小人工维护成本,同时为代码的维护迭代提供保障。
前端自动化测试的方向有:单元测试、UI回归测试、功能测试、性能测试。
RegularUI采用karma+mocha的单元测试,ant-design使用Jest的snapshot测试与模拟用户的功能测试相结合的方式。
PhantomFlow是基于决策树的,对PhantomJS, CasperJS, PhantomCSS的包装。以简单的方式描述用户操做流。并配以CasperJS的页面操做,PhantomCSS的截图,达到很是好的自动化测试效果。
测试时要保证数据的肯定性和添加适当的断言。
CI是一种好的软件工程思想。Travis CI简单易用,解放了开发人员手动运行测试,很是值得在项目中引入。