验收测试 - WebDriver 5
验收测试 - WebDriver - 配置
什么是WebDriver
这样说好了,它翻译起来就是Web驱动
,用我的经验来说,它就是驱动浏览器运行的一个驱动器
有什么作用?
就像一个司机可以驱动一台汽车行使一样,WebDriver可以驱动一个浏览器做浏览器可以做的事情(跳转页面,点击链接,划过选项卡...)
这些操作平时一般是我们人来操作的,但现在可以由WebDriver来操作
最终,它能将我们之前验收测试的代码传达给浏览器,让浏览器自动点击链接,断言页面是否有特定内容
WebDriver是一个模块,需要我们配置才可以使用,而且它不能和PhpBrowser
模块一齐使用,下面我们以调用Chrome浏览器自动化测试为例子配置一下
需要准备以下软件:
-
Chrome浏览器,这个如果百度搜索Chrome的官网下载可能不一定成功,因为下载来的是一个"下载器",再由这个下载器通过国外线路下载这个浏览器的安装包本体,这个线路经常被祖国屏蔽.就连我自己都是靠XX软件管家或者太平洋软件站这些平台得到下载安装的.另外包装了Webkit内核的360极速浏览器,QQ浏览器,猎豹浏览器之类的不行,必须是 Chrome浏览器
-
JDK6或以上版本
-
Selenium服务器,它是一个Java软件包,推荐下载我共享到百度云的文件就行了,地址是http://pan.baidu.com/s/1R3EA6就行了,顺便提供一个官网地址http://seleniumhq.org/download
-
谷歌浏览器驱动(chromedriver.exe),以下是几个获取方式:
-
也是推荐到百度云地址http://pan.baidu.com/s/1gemYiVD下载我共享的就行了
-
觉得我共享的那个可能有病毒的话可以自行到官网下载
-
到淘宝镜像站http://npm.taobao.org/mirrors/chromedriver下载最新版本
-
开始动手配置
-
将下载来的Selenium服务器软件包(selenium-server-standalone-版本号.jar)放到E盘根目录下吧,暂时先跟我这样放,以后你自己调整也行
-
将下载来的谷歌浏览器驱动(chromedriver.exe)放到谷歌浏览器那个exe相同的目录,比如我的安装目录是
C:\Program Files (x86)\Google\Chrome
,这个目录的Application
子目录里面有浏览器的主程序chrome.exe
,然后把刚下载的那个文件也放这里与主程序一起就好了 -
把chrome.exe所在的目录追加到系统环境变量PATH里
-
打开
acceptance.suite.yml
,将PhpBrowser这个模块名称换成WebDriver,并且记得也将modules - config - PhpBrowser
这个PhpBrowser也给换掉,并且在modules - config
配置下增加browser
配置项,值为chrome
,最终文件应该是像我这样的内容:class_name: AcceptanceTester modules: enabled: - WebDriver - AcceptanceHelper config: WebDriver: url: http://www.kkh86.com browser: chrome
由于这里我们将PhpBrowser模块换成了WebDriver模块,只要有模块变更就要重新构造测试器,还是以前的命令,关键就是build那里,我再重复一遍:
cd E:\project1-tests php E:\codecepr.phar build
运行build命令之后
tests/acceptance/AcceptanceTester.php
里的代码应该会发生变化,如果你有备份build之前的代码就可以对比一下
验证配置是否正确
做完以上的配置之后,我们开始验证一下配置得对不对,接下来我们要启动Selenium服务器,打开命令行,cd到E盘,然后执行
java -jar selenium-server-standalone-版本号.jar
接着下面就会哗哗地冒出好多程序输出内容,这里就表示Selenium服务器应该已经启动了,你不要关闭这个命令行窗口,不然Selenium服务器也会停止的哦,再是为了确认它是否真的启动成功,访问http://127.0.0.1:4444/wd/hub 这个地址,如果有一个英文小页面即证明成功了
修改我们以前的那个教学用的IndexPageCept.php
这个测试用例,将代码改成这样的:
use project1_tests\AcceptanceTester;
$I = new AcceptanceTester($scenario);
$I->amOnPage('/');
$I->see('我叫KK');
$I->click('文章');
$I->seeCurrentUrlEquals('/article/list.html');
然后运行测试用例,正常的话稍等几秒应该会运行一个谷歌浏览器并打开被测试的网站,按照PHP代码去进执行的
可是如果浏览器没有被正常运行的话,根据大家的反馈判断很可能是驱动文件没被正确加载,你可以试下用这个命令启动Selenium服务器:
java -jar selenium-server-standalone-版本号.jar -Dwebdriver.chrome.driver="谷歌驱动所在的目录\chromedriver.exe"
好了,如无意外,就基于这个配置,接着一起学习后面的WebDriver级别的验收测试吧^-^
验收测试 - WebDriver - 驱动火狐浏览器
本节教大家如何让测试代码调起火狐浏览器
可以说这个绝对比调起谷歌浏览器更加容易,因为Codeception默认就是启动火狐浏览器的,先试试
-
WebDriver模块的配置:
modules: enabled: - WebDriver - AcceptanceHelper config: WebDriver: url: http://www.kkh86.com
没错,这配置还不用声明browser,默认就是Firefox
-
将最新版火狐浏览器安装到默认目录(安装时一般默认到C盘的)
-
下载最新的Selenium服务器jar包,一定要最新Firefox+最新Selenium,否则我不保准能驱动起来
-
运行测试代码即可
就是这么简单
缺点
-
运行慢,火狐浏览器的启动速度目前来说明显是比Chrome慢很多的,然后是页面的交互也不是很快
-
火狐浏览器的版本经常换几换就不支持现有的Selenium服务器了
你要赶紧下载最新版Selenium.jar才可以将最新火狐浏览器驱动起来,这是我的使用感受
但是谷歌浏览器没这么频繁
不过最后,我干脆就不更新测试用的浏览器和Selenium了,除非很有必要
而平时上网就用国产的浏览器极速模式就是了,这个可以爱更新就更新
最终就是不推荐用火狐运行测试,效率嘛
不过有部分人还是挺喜欢火狐浏览器的,从使用功能上来说,其实我也好喜欢啊,就是运行速度开始接受不了
大家有兴趣的话可以多试试二者的测试情况,时间长了自然就有感受了
关于驱动IE
这其实也是可以做到的,并且我已经安排过工作人员实现,但已经不记得具体的流程了
其中也是要到微软官方下载驱动的,这里我不会有教程内容,有必要的请自己研究,或者去JAVA界的WebDriver测试领域请教那些人应该有人给到解答
使用的效果就是:很多火狐和谷歌都表现一致的测试反应,在IE里就是不一致,特别是DOM的查找问题上
验收测试 - WebDriver - 介绍
WebDriver的验收测试和基础的验收测试区别很明显,一个是模拟浏览器而且不能运行JS,仅仅对DOM文档做断言,一个是直接调用浏览器,将PHP代码翻译成浏览器可以理解的东西让浏览器动起来,这是表现上的区别.
而编程上,区别其实并不大,代码非常相似,即使是使用了真实浏览器,也依然要声明"我要跳转到哪个页面",即$I->amOnPage(...)
;也依然要说明"我能看到某个Dom元素",即$I->seeElement('#login')
下面列出基础验收测试和WebDriver验收测试都能使用的公共方法名称,大家可以直接将这些方法继续使用在WebDriver验收测试的开发上,但这里不是全部都列出,只是把经常用到的列出,完整的差异请大家自行查看AcceptanceTester
,这个类我重复提到过几次了,这是最后一次,希望不熟练的朋友可以注意到这个类在你不熟悉测试方法的时候有多么大帮助.
-
amOnPage($page)
-
amOnSubdomain($subdomain)
-
amOnUrl($url)
-
attachFile($field, $filename)
-
checkOption($option)
-
click($link, $context = null)
-
grabTextFrom($cssOrXPathOrRegex)
-
grabValueFrom($field)
-
see($text, $selector = null)
-
canSee($text, $selector = null)
其它一堆can系列和dont系列的see断言我就不列举了 -
seeCheckboxIsChecked($checkbox)
-
seeInField($field, $value)
-
seeCookie($name)
-
seeElement($selector, $attributes = null)
-
seeInCurrentUrl($uri)
-
seeInTitle($title)
-
seeLink($text, $url = null)
-
seeNumberOfElements($selector, $expected)
-
seeOptionIsSelected($selector, $optionText)
-
selectOption($select, $option)
-
submitForm($selector, $params, $button = null)
验收测试 - WebDriver - 执行JS
在WebDriver的验收测试下,如果一个页面包含了JS代码,那么被浏览器加载了页面的时候自然就会运行,不然你怎么能看到页面上的各种DOM被完整地渲染?你试试
$I->amOnUrl('http://www.qq.com'); //切换域名
$I->amOnPage('/'); //进入首页
$I->wait(10); //暂停10秒
然后你可以看到浏览器完整地显示了腾讯首页,这个首页当然有JS的了,比如一些广告加载的JS,一些天气JS,日期提示JS...各种,自己查看浏览器页面源代码就能看到好多
执行自定义JS
你可以在PHP代码里写一些JS代码字符串传达给浏览器执行,比如这样:
$jsCode = 'document.body.innerHTML = "嘿嘿,我是来自PHP的捣乱者!";';
$I->executeJs($jsCode);
$I->wait(3); //暂停3秒,因为如果不暂停的话,执行完最后一句测试代码就会马上关掉浏览器,所以我特地加上这个代码让你多看几秒效果而已,免得一闪而过似有似无
而且这些JS代码与页面上的JS是处于同一个沙箱里的,于是可以互相调用,假设页面上引入了 jQuery
$jsCode = <<<JS
var div = $('<div style="height:100px;background:red;"></div>');
$('body').html(div);
div.animate({
height : '800px'
}, 5000);
JS;
$I->executeJs($jsCode);
$I->wait(6);
$I->executeJs('$("#login").click()');
来来来,我们还可以把页面的数据抓上来:
$linksHtml = $I->executeJs('return $("body a").html()');
file_put_contents('links.html', $linksHtml);
$payMoney = $I->executeJs('return $("#payMoney").val()'); //假设页面上有个支付金额的表单
codecept_debug($payMoney);
拿到页面数据后你爱干嘛就是另一回事咯,但注意,你的JS代码如果使用了jQuery,那你要确保页面上已经加载了jQuery
验收测试 - WebDriver - 模拟击键
比如我们要测试一个名字输入框在输入超过10个文字长度时会不会有红色提示,用这个代码来实现模拟输入
$I->pressKey('#name', '一二三四五六七八九十呀');
实例:
$I->see('', '#warningTips'); //先断言目前没有错误提示
$I->pressKey('#username', 'kfkkwkwkwkekerjrjrh'); //模拟输入一个很长的用户名字符串
$I->see('请输入2到10个字符的用户名', '#warningTips'); //断言会出现用户名长度警告
验收测试 - WebDriver - 注意隐藏元素!
这个真是很重要,你务必知道!
假设 #menu1 菜单是划过 #xxx 区域才会显示出来,划开后就会自动隐藏,那么在未划过的时候,不可见,如果你使用
$I->click('#menu1');
这样是不会发生任何页面跳转或菜单效果的!因为这是模拟真人操作浏览器,你看不到菜单的时候点不到,要划过去让它显示出来才能点,所以机器和你也一样
于是你应该像这样先划过 #xxx 区域让它出来了再执行点击的哦!
$I->moveMouseOver('#xxx'); //模拟划过
$I->seeElement('#menu1'); //同时,显示了才可见,隐藏不能see,其它see方法都是
$I->click('#menu1');
这里还没完,补充一下,你可以通过第2和3个参数微调模拟划过的位置
$I->moveMouseOver('#xxx', 10); //在x轴上向右偏移10个像素点,负数向左
$I->moveMouseOver('#xxx', 0, 20); //在y轴上向下偏移20个像素点,负数向上
$I->moveMouseOver('#xxx', 30, 30); //你懂的
当你以后运行时老是发现点击/断言不到一个元素时,请检查这个元素是不是已经显示出来了!
验收测试 - WebDriver - 等待与暂停
-
$I->wait(10)
等待10秒,但是10秒后会恢复继续运行 -
$I->waitForElement('#tab2', 10)
等待一个特定元素出现时才继续运行,最多等待10秒,如果不传第二个参数(秒数)的就是永远等待,直到服务器不耐烦报timeout等错误为止... -
$I->waitForElementChange('#count')
等等某个元素发生改变时才运行,或者下面这个小例子是等待一个菜单出现才继续运行$I->waitForElementChange('#menu', function(\WebDriverElement $element) { return $element->isDisplayed(); //判断是否显示,之所以这样写是暗示你可以用$element做很多事情哦,自己研究吧~ }, 1000);
其中第3个参数是最大等待秒数,可以不传
-
$I->waitForElementVisible('#menu')
这也是等待一个元素直到它可以看见为止,是上面那个代码的便捷版 -
$I->waitForElementNotVisible('#menu')
这是相反,等待一个元素直到它不可见为止 -
$I->waitForJS('return winnerNums == 200;')
等待这条JS表达式为true时再执行,比如现在有个数据显示区实时显示胜出的人数,191,192,193...地慢慢增加,而且有个全局JS变旱winnerNums
保存这个数据,在200之前不成立,则一直在等待,加到200后测试用例就会解除等待,继续往下跑了 -
$I->waitForText('你有一条新消息', 10, '#newMsgPannel')
等待特定的文本出现在页面上的#newMsgPannel元素里面,最多等待10秒,其中第2和第3个参数可以不传,只要指定文本即可,它会全局慢慢查,只是慢一点
暂停测试脚本
在涉及一些复杂的数据增删改然后你又在调试时这个比较有用,方法名pauseExecution
$I->click('#finishStep1');
$I->pauseExecution(); //点击添加后暂停一下,然后你可以自行到数据库查看些数据确认或者其它事情
$I->click('#next');
$I->fillField('...各种表单填充');
$I->click('#finishStep2');
$I->pauseExecution(); //又来..
但其实你可能会问:那跟我人工测试有啥区别?我自己也可以点一下链接看一下数据库再点下一个链接也是暂停继续暂停继续的操作呀
确实,一般情况下你自己都可以做到,要这种代码配合的不是很常有,但是这个代码是已经预先设定好了的流程,你人工操作的话可能会少一个流程,在一些OA系统,ERP系统,比较多商品和多支付模式的商品交易中你想想是不是你人工都记得住每一个流程的环节而不漏掉测试呢?但这时候电脑全部都记得,它只是慢慢运行,帮你一次次停下来,你只管根据它的测试流程去查数据做微调就好了
验收测试 - WebDriver - 页面与弹框
在yml配置文件中的WebDriver模块配置项里增加一个window_size
选项可以设置测试时使用哪个窗口大小来测试,单位是像素值,值也很简单,例如
window_size: 1024x768
页面和窗口操作
如果要测试链接的新窗口,你也不用勉强把a标签的target属性改掉来折衷配合测试,而是可以通过grab系列方法或者执行JS获取所需要的a标签的href属性,再用amOnPage强换过去,这样就实现了本窗口跳转了.
这是对超级链接新窗口的说明,但是下面介绍的一些关于页面的操作,switchToWindow则不是对超级链接新窗口的,请慢慢看:
-
$I->reloadPage()
重新加载页面,跟JS的location.reload()一样 -
$I->resizeWindow(800, 600)
调整浏览器窗口大小到800*600像素 -
$I->maximizeWindow()
最大化浏览器 -
$I->makeScreenshot('user-info')
将当前浏览器的画面保存一张截图快照到tsts/_output/debug
目录下,参数是图片前缀名,这里将会保存到 tests/_output/debug/user-info.png 注意是保存为png格式的哦. -
$I->switchToWindow('windowName')
切换到一个特定的窗口,比如当页面上执行了window.open('http://www.xxx.com', 'name1');
的话,就是给新打开的窗口起了个叫name1
的名字做标识,然后测试时通过这个名字来切换到新窗口(就像用鼠标点击了新窗口的标签一样切换过去),因为如果你不切换过去的话是无法断言新窗口的东西的.当你测试完这个新窗口后要回到原来的窗口则是再执行一下这个方法,但不要传参数就可以回到上一个窗口.类似这个的后面还有个测试iframe的章节也有提到
验收测试 - WebDriver - 测试iframe
如果页面上有iframe,那么平时对一些元素做查找断言的时候是找不到它的,默认情况只在页面文档最顶层做搜索.要测试iframe里的东西就先要将测试者的当前位置切换到iframe里,例如以下代码:
$I->switchToIFrame('leftMenu'); //leftMenu 是iframe的name属性值,不是ID属性,只支持name值定位
然后再像平时一样继续seeElement,see什么的呵呵,你只要知道自己当前是在iframe的url里就行了.其实我认为这样跟$I->amOnPage($iframe的URL)
效果差不多.
区别是,如果iframe和父页面有JS交互通讯行为,则你不能amOnPage来强制切换,因为你要断言一些操作造成JS交互后的变化
如果你已经切换到一个iframe里面了,则如果要切换回外面父页面的话就还是用这个方法,但不用传递参数就是回到上一级页面,有N个上一级都可以这样做,但不是回到顶层,只是上一级哦
$I->switchToIFrame();
验收测试 - WebDriver - 多会话测试
这是比较少需要用到的功能,但偶尔真的需要它
假设你要测试一个社交网站,要测试A用户向B用户发起好友请求后,B用户是否有收到并且可以同意成为好友,那你的测试代码click添加好友后,怎么断言B是否已经收到?以之前提供的教程信息,你只能靠Db模块来seeInDatabase,虽然我认为一般都是在内网部署测试项目,针对测试环境做测试,所以可以共享数据库,但是测试框架怎么能这么限制你呢?
于是肯定要支持你数据库不在本地时也能做到这样的测试
办法就是当模拟A用户发起好友请求后,使用haveFriend方法临时创建B用户并将session切换到B用户中进行断言,断言结束后再切换回A用户中,这就像是多窗口测试和iframe测试一样,临时切换到另一个空间中就好了.
实践
假设当前登陆用户的名称叫 小明
$I->click('#发送好友请求');
$friend = $I->haveFriend('friend1'); //创建一个新的会话,参数是一个唯一的标识符,因为你可以创建很多会话,为了识别每一个会话就要为它们起不同的名字以便切换和互相通信之类的
$friend->does(function(AcceptanceTester $I){
//这个函数区域内是$friend的事情
$I->amOnPage('/new-msg.html');
$I->see('小明请求成为你的朋友');
$I->click('.accept:nth-child(1)'); //点击同意按钮
});
$I->waitForElemenet('#newMessage'); //等待新消息提示的DOM出现.这里你要知道上面的does方法部分不是先执行完才执行这里的,这里其实并不会被does方法阻塞,而是继续往下执行,所以我们要waitForElement
$I->see('小红同意了你的好友请求');