有了上一节的基础后,下面我们就开始动手搭建自己的自动化测试环境。这也是我们实施自动化测试的准备工作,本书选用 python 语言,如果读者选用的其它语言,请参考其它资料进行环境的搭建。
下载 python【python 开发环境】
http://python.org/getit/
下载 setuptools 【python 的基础包工具】
http://pypi.python.org/pypi/setuptools
下载 pip 【python 的安装包管理工具】
https://pypi.python.org/pypi/pip
要想使用 python 语言开发,首先需要 python 开发环境,需要说明的是 python 目前最新版本分:2.7.x
和3.3.x(简称 python 2 和 python 3);python 3 并非完全的向下兼容 python 2 ,语法上也有较大的
差异。python 3在性能上更加优秀,但由于 python 2多年的发展,大量的类库、框架是基于 python 2,
所以,目前两个版本都在维护更新。笔者推荐新手从 python 2开始学习 python,因为有丰富的资料、类
库和框架给我们学习和使用。当然,随着时间的推移,python 3 才是 python 发展的未来。
setuptools 是 python 的基础包工具,可以帮助我们轻松的下载,构建,安装,升级,卸载 python的软件包。
pip 是python软件包的安装和管理工具,有了这个工具,我们只需要一个命令就可以轻松的python 的任意类库。
第一步、安装 python 的开发环境包,选择需要安装路径进行安装,笔者下载的是目前最新的
python2.7.5版本,安装目录为:C:\Python27。
第 二 步 、 安 装 setuptools 通 过 前 面 提 供 的 setuptools 的 连 接 , 拖 动 页 面 到 底 部 找 到 ,
setuptools-1.3.2.tar.gz 文件(版本随着时间版本会有更新),对文件进行解压,找到 ez_install.py
文件,进入 windows 命令提示(开始–运行–cmd 命令,回车)下执行 ez_install.py:
C:\setuptools-1.3>python ez_install.py
如果提示 python 不是内部或外部命令!别急,去添加一下 python 的环境变量吧!桌面“我的电脑”
右键菜单–>属性–>高级–>环境变量–>系统变量中的 Path 为:
变量名:PATH
变量值:;C:\Python27
第三步、安装 pip ,通过上面提供的链接下载 pip-1.4.1.tar.gz(版本随着时间版本会有更新),我默认解压在了 C:\pip-1.4.1 目录下,打开命令提示符(开始–运行–cmd 命令,回车)进入 C:\pip-1.4.1目录下输入:
C:\pip-1.4.1 > python setup.py install
再切换到 C:\Python27\Scripts 目录下输入:
C:\Python27\Scripts > easy_install pip
第四步、安装 selenium,如果是电脑处于联网状态的话,可以直接在 C:\Python27\Scripts 下输入
命令安装:
C:\Python27\Scripts > pip install -U selenium
如果没联网,可以通过下载安装:
selenium 下载地址: https://pypi.python.org/pypi/selenium
下载 selenium 2.33.0 (目前的最新版本),并解压把整个目录放到 C:\Python27\Lib\site-packages
目录下。
下面以 unbuntu 为例进行安装,其它版本的 linux 可能会有所差异,在绝大多数 linux 和 UNIX 系统安装中(包括 Mac OS X),Python 的解释器就已经存在了。我们需要做的就是打开终端,输入 python 命令进行验证,这里不再介绍 python 的安装。
第一步、安装:setuptools
root@fnngj-H24X:~# apt-get install python-setuptools
第二步、安装 pip
下载 pip 安装文件,切换到文件目录,对其进行解压:
root@fnngj-H24X:/home/user/python# tar -zxvf pip-1.4.1.tar.gz
切换到解压目录:
root@fnngj-H24X:/home/user/python# cd pip-1.4.1/
进行 pip 的安装
root@fnngj-H24X:/home/user/python/pip-1.4.1# python setup.py install
第三步、安装 selenium
root@fnngj-H24X:/home/user/python/pip-1.4.1# pip install -U selenium
相信上面的配置过程已经让不少新手感到非常繁琐,万事开头难,我们有必要花一点时间在环境的配
置上,因为环境的搭建是后面实施自动化测试的前提。
如果笔者是第一次接触 python 语言且编程能力薄弱,那么笔者建议使用 python 自带的 IDLE 来编写
脚本。为了更好的通过 IDLE 帮助们编写 python+webdriver 脚本,我们需要先了解一下 IDLE。
IDLE 提供了一个功能完备的代码编辑器,允许你在这个编辑器中编写代码,另外还有一个 python
shell(python 的交互模式),可以在其中试验运行代码。
第一次启动 IDLE 时,会显示“三个大于号”提示符(>>>),可以在这里输入代码。python shell 得
到你的代码语句后会立即执行,并在屏幕上显示生成的结果。如图
IDLE 提供了大量的特性,不过只需了解其中一小部分就能很好地使用 IDLE。
TAB 完成:
先键入一些代码,然后按下 TAB 键。IDLE 会提供一些建议,帮助你完成这个语句。
回退代码语句:
按下 Alt+P,可回退到 IDLE 中之前输入的代码语句,或者按下 Alt+ N 可以移至下一个代码语句。
如图 2.x 按 Alt+P 回退到上一次编辑的代码。
有了上面的环境,你一定很迫切想要编写并运行一个自动化脚本,下面就来体验一下 python 与wegdriver 结合之后编写的脚本是多么简洁:
如果是 windows 用户,在开始菜单找到 python 目录,打开 IDLE(python GUI)程序,启动的是一个
交互模式。可以输入:from selenium import webdriver
上面的命令为导入 selenium 的相关包,如果回车后没有报错表示我们的 selenium 安装是成功的。
下面通选择菜单栏 File—>New Windows 或通过快捷键 Ctrl+N 打开新的窗口。输入以下代码:
# coding = utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
输入完成后命令为 baidu.py 保存,按 F5 快捷键运行脚本,将看到脚本启动 Firefox 浏览器进入百度页,
输入“selenium” 点击搜索按钮,最后关闭浏览器的过程。(这里默认读者已经安装了 Firefox 浏览器)
我们后面的脚本也将会在这个编辑器下完成,在你还没找到更好的编辑器之前。
#coding = utf-8
为了防止乱码问题,以及方便的在程序中添加中文注释,把编码统一成 UTF-8。
from selenium import webdriver
导入 selenium 的 webdriver 包,只有导入 webdriver 包我们才能使用 webdriver API 进行自动化脚本
的开发。 import 所引入包,更专业的叫法为:模组(modules)
browser = webdriver.Firefox()
需要将控制的 webdriver 的 Firefox 赋值给 browser;获得了浏览器对象才可以启动浏览器,打开网址,操作页面严肃,Firefox 是默认已经在 selenium webdriver 包里了,所以可以直接调用。当然也可以调用 Ie 或 Chrome ,不过要先安装相关的浏览器驱动才行。
browser.get(“http://www.baidu.com”)
获得浏览器对象后,通过 get()方法,可以向浏览器发送网址。
browser.find_element_by_id(“kw”).send_keys(“selenium”)
关于页面元素的定位后面将会详细的介绍,这里通过 id=kw 定位到百度的输入框,并通过键盘方法
send_keys()向输入框里输入 selenium 。多自然语言呀!
browser.find_element_by_id(“su”).click()
这一步通过 id=su 定位的搜索按钮,并向按钮发送单击事件( click() )。
browser.quit()
退出并关闭窗口的每一个相关的驱动程序。
WebDriver 支持 Firefox (FirefoxDriver)、IE (InternetExplorerDriver)、Opera (OperaDriver) 和Chrome (ChromeDriver) 。 对 Safari 的 支 持 由 于 技 术 限 制 在 本 版 本 中 未 包 含 , 但 是 可 以 使 用SeleneseCommandExecutor 模拟。它还支持 Android (AndroidDriver)和 iPhone (IPhoneDriver) 的移动
应用测试。它还包括一个基于 HtmlUnit 的无界面实现,称为 HtmlUnitDriver。
各个浏览器驱动下载地址:
https://code.google.com/p/selenium/downloads/list
安装 chrome 浏览器驱动,下载 ChromeDriver_win32.zip(根据自己系统下载不同的版本驱动),解压
得到 chromedriver.exe 文件放到环境变量 Path 所设置的目录下,如果前面我们已经将(C:\Python27 )
添加到了环境变量 Path 所设置的目录,可以将 chromedriver.exe 放到 C:\Python27\目录下。
安装 IE 浏览器驱动,下载 IEDriverServer_Win32_x.xx.zip,将解压得到 IEDriverServer.exe,同样
放置到 C:\Python27\目录下。
liunx 系统下,同样下载系统对应的浏览器驱动,并将驱动放置到环境变量 Path 所设置的目录下,
这里不再详细介绍。
安装完成后可以用 IE 和 chrome 来替换 firefox 运行上面的例子。
browser = webdriver.Firefox()
替换为:
browser = webdriver.Ie()
或
browser = webdriver.Chrome()
如果程序能调用相应的浏览器运行,说明我们的浏览器驱动安装成功。
OperaDriver 是 WebDriver 厂商 Opera Software 和志愿者开发了对于 Opera 的 WebDriver 实现。安装
方式与 IE、chrome 有所不同;请参考其它文档进行安装。
这一章将详细的讲解基于 python 的 webdriver API,笔者更愿意读者自已去查询 webdriver API 中各种操作方法的使用,为了保持本书由浅入深的完整性,本章将用相当有篇幅介绍基于 python 语言的webdriver 对种操作的使用。通过本章的学习,我们掌握 web 页面上各种元素、弹窗的定位与操作,以及浏览器 cookie 的操作,JavaScript 的调用等问题。
在统一的浏览器大小下运行用例,可以比较容易的跟一些基于图像比对的工具进行结合,提升测试的
灵活性及普遍适用性。比如可以跟 sikuli 结合,使用 sikuli 操作 flash。
#coding=utf-8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
print "浏览器最大化"
driver.maximize_window() #将浏览器最大化显示
driver.quit()
在不同的浏览器大小下访问测试站点,对测试页面截图并保存,然后观察或使用图像比对工具对被测页面的前端样式进行评测。比如可以将浏览器设置成移动端大小(320x480),然后访问移动站点,对其样式进行评估;
#coding=utf-8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://m.mail.10086.cn")
#参数数字为像素点
print "设置浏览器宽480、高800显示"
driver.set_window_size(480, 800)
driver.quit()
浏览器上有一个后退、前进按钮,对于浏览网页的人是比较方便的;对于 web 自动化测试来说是一个比较难模拟的操作;webdriver 提供了 back()和 forward()方法,使实现这个操作变得非常简单。
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
#访问百度首页
first_url= 'http://www.baidu.com'
print "now access %s" %(first_url)
driver.get(first_url)
#访问新闻页面
second_url='http://news.baidu.com'
print "now access %s" %(second_url)
driver.get(second_url)
#返回(后退)到百度首页
print "back to %s "%(first_url)
driver.back()
#前进到新闻页
print "forward to %s"%(second_url)
driver.forward()
driver.quit()
为了使脚本的执行过程看得更清晰,在每一步操作上都加了 print 来打印当前的 URL 地址。
运行结果如下:
>>> ================================ RESTART ================================
>>>
now access http://www.baidu.com
now access http://news.baidu.com
back to http://www.baidu.com
forward to http://news.baidu.com
实际测试中,这两个功能平时很少被使用,笔者所能想到的场景就是几个页面来回跳转,但又不想用
get url 的情况下。
下面打开 python shell 做以下练习:
>>> name = 'huhu'
博客园---虫师
http://fnng.cnblogs.com 34
>>> age = 26
>>> print "my name is %s" %name
my name is huhu
>>> print "my age is %d" %age
my age is 26
>>> print "my name is %d" %name
Traceback (most recent call last):
File "" , line 1, in <module>
print "my name is %d" %name
TypeError: %d format: a number is required, not str
>>> print "my name is %s ,age is %d" %(name,age)
my name is huhu ,age is 26
在 python 2 中使用 print 语句进行打印输出,如果是字符信息的话需要对打印的信息加单引号(‘’)或双引号(“”),它们本质上没有任何区别,不过使用引号时必须要成对出现。
上面的例子中我们定义一个字符串变量 name 和一个数据变量 age,要想在 print 打印字符串中引用这
两个变量就要用到“格式化字符串”的东西,在 print 打印字符串中指定变量类型,“%s”表示输出的类型为字符串,“%d”表示输出类型为整型数字。
name 为字符串类型,我们用%d 来指定输出类型就会报错。如果我们不确定变量类型的话可以使用%r,它的含义是“不管什么都打印出来”。
对象(元素)的定位和操作是自动化测试的核心部分,其中操作又是建立在定位的基础上的,因此元
素定位就显得非常重要。(本书中用到的对象与元素同为一个事物)
一个对象就像是一个人,他会有各种的特征(属性),如比我们可以通过一个人的身份证号、姓名或
者他的住址找到这个人。那么一个元素也有类似的属性,我们可以通过这种唯一区别于其它元素的属性来定位这个元素。当然,除了要操作元素时需要定位元素外,有时候我们只是为了获得元素的属性(class 属性,name 属性)、text 或数量也需要定位元素。
webdriver 提供了一系列的元素定位方法,常用的有以下几种
id 和 name 是我们最常用的定位方式,因为大多数元素都有这两个属性,而且在对控件的 id 和 name
命名时一般使其有意义也会取不同的名字。通过这两个属性使我们找一个页面上的属性变得相当容易。
<input id="gs_htif0" class="gsfi" aria-hidden="true" dir="ltr">
<input type="submit" name="btnK" jsaction="sf.chk" value="Google 搜索">
<input type="submit" name="btnI" jsaction="sf.lck" value=" 手气不错 ">
通过元素中所带的 id 和 name 属性对元素进行定位:
id=”gs_htif0”
find_element_by_id(“gs_htif0”)
name=”btnK”
find_element_by_name(“btnK”)
name=”btnI”
find_element_by_name(“btnI”)
不是所有的前端开发人员都喜欢为每一个元素添加 id 和 name 两个属性,但除此之外你一定发现了一
个元素不单单只有 id 和 name,它还有 class 属性;而且每个元素都会有标签。
<div id="searchform" class="jhp_big" style="margin-top:-2px">
<form id="tsf" onsubmit="return name="f" method="GET" action="/search">
<input id="kw" class="s_ipt" type="text" name="wd" autocomplete="off">
通过元素中带的 class 属性对元素进行定位:
class=”jhp_big”
find_element_by_class_name(“jhp_big”)
class=”s_ipt”
find_element_by_class_name(“s_ipt”)
通过 tag 标签名对对元素进行定位:
< div>
find_element_by_tag_name(“div”)
< form>
find_element_by_tag_name(“form”)
< input>
find_element_by_tag_name(“input”)
tag name 定位应该是所有定位方式中最不靠谱的一种了,因为在一个页面中具有相同 tag name 的元
素极其容易出现。
有时候需要操作的元素是一个文字链接,那么我们可以通过 link text 或 partial link text 进行元素
定位。
<a href="http://news.baidu.com" name="tj_news">新 闻</a>
<a href="http://tieba.baidu.com" name="tj_tieba">贴 吧</a>
<a href="http://zhidao.baidu.com" name="tj_zhidao">一个很长的文字连接</a>
通过 link text 定位元素:
find_element_by_link_text(“新 闻”)
find_element_by_link_text(“贴 吧”)
find_element_by_link_text(“一个很长的文字连接”)
通 partial link text 也可以定位到上面几个元素:
find_element_by_partial_link_text(“新”)
find_element_by_partial_link_text(“吧”)
find_element_by_partial_link_text(“一个很长的”)
当一个文字连接很长时,我们可以只取其中的一部分,只要取的部分可以唯一标识元素。一般一个页
面上不会出现相同的文件链接,通过文字链接来定位元素也是一种简单有效的定位方式。
下面介绍 xpath 与 CSS 定位相比上面介绍的方式来说比较难理解,但他们的灵活性与定位能力比上
面的方式要强大。
XPath 是一种在 XML 文档中定位元素的语言。因为 HTML 可以看做 XML 的一种实现,所以 selenium 用户可是使用这种强大语言在 web 应用中定位元素。
XPath 扩展了上面 id 和 name 定位方式,提供了很多种可能性,比如定位页面上的第三个多选框。
<html class="w3c">
<body>
<div class="page-wrap">
<div id="hd" name="q">
博客园---虫师
http://fnng.cnblogs.com 38
<form target="_self" action="http://www.so.com/s">
<span id="input-container">
<input id="input" type="text" x-webkit-speech="" autocomplete="off"
suggestwidth="501px" >
我们看到的是一个有层级关系页面,下面我看看如果用 xpath 来定位最后一个元素。
用绝对路径定位:
find_element_by_xpath(“/html/body/div[2]/form/span/input”)
当我们所要定位的元素很难找到合适的方式时,都可以通这种绝对路径的方式位,缺点是当元素在很
多级目录下时,我们不得不要写很长的路径,而且这种方式难以阅读和维护。
相对路径定位:
find_element_by_xpath(“//input[@id=’input’]”) #通过自身的 id 属性定位
find_element_by_xpath(“//span[@id=’input-container’]/input”) #通过上一级目录的id属性定位
find_element_by_xpath(“//div[@id=’hd’]/form/span/input”) #通过上三级目录的 id 属性定位
find_element_by_xpath(“//div[@name=’q’]/form/span/input”)#通过上三级目录的 name 属性定位
通过上面的例子,我们可以看到 XPath 的定位方式非常灵活和强大的,而且 XPath 可以做布尔逻辑运算,例如://div[@id=’hd’ or @name=’q’]
当然,它的缺陷也非常明显:1、性能差,定位元素的性能要比其它大多数方式差;2、不够健壮,XPath会随着页面元素布局的改变而改变;3. 兼容性不好,在不同的浏览器下对 XPath 的实现是不一样的。
通过我们第一章中介绍的 firebug 的 HTML 和 firePath 可以非常方便的通过 XPath 方式对页面元素进
行定位。
打开 firefox 浏览器的 firebug 插件,点击插件左上角的鼠标箭头,再点击页面上的元素,firebug
插件的 HTML 标签页将看到页面代码,鼠标移动到元素的标签上(如图图3.1,)将显示当前元素的绝对路径。
或者直接在元素上右击弹出快捷菜单,选择 Copy XPath,将当前元素的 XPath 路径拷贝要脚本
本中(如图)。
firePath 工具的使用就更加方便和快捷了,选中元素后,直接在 XPath 的输入框中显示当前元素的
XPath 的定位信息(如图3.3)。
CSS(Cascading Style Sheets)是一种语言,它被用来描述 HTML 和 XML 文档的表现。CSS 使用选择器来为页面元素绑定属性。这些选择器可以被 selenium 用作另外的定位策略。
CSS 可以比较灵活选择控件的任意属性,一般情况下定位速度要比 XPath 快,但对于初学者来说比较
难以学习使用,下面我们就详细的介绍 CSS 的语法与使用。
CSS 选择器的常见语法:
* | 通用元素选择器,匹配任何元素 |
E | 标签选择器,匹配所有使用 E 标签的元素 |
.info | class 选择器,匹配所有 class 属性中包含 info 的元素 |
#footer | id 选择器,匹配所有 id 属性等于 footer 的元素 |
E,F | 多元素选择器,同时匹配所有 E 元素或 F 元素,E 和 F 之间用逗号分隔 |
E F | 后代元素选择器,匹配所有属于 E 元素后代的 F 元素,E 和 F 之间用空格分隔 |
E > F | 子元素选择器,匹配所有 E 元素的子元素 F |
E + F | 毗邻元素选择器,匹配紧随 E 元素之后的同级元素 F (只匹配第一个) |
E ~ F | 同级元素选择器,匹配所有在 E 元素之后的同级 F 元素 |
E[att=‘val’] | 属性 att 的值为 val 的 E 元素 (区分大小写) |
E[att^=‘val’] | 属性 att 的值以 val 开头的 E 元素 (区分大小写) |
E[att$=‘val’] | 属性 att 的值以 val 结尾的 E 元素 (区分大小写) |
E[att*=‘val’] | 属性 att 的值包含 val 的 E 元素 (区分大小写) |
E[att1=‘v1’][att2*=‘v2’] | 属性 att1 的值为 v1,att2 的值包含 v2 (区分大小写) |
E:contains(‘xxxx’) | 内容中包含 xxxx 的 E 元素 |
E:not(s) | 匹配不符合当前选择器的任何元素 |
例如下面一段代码:
<div class="formdiv">
<form name="fnfn">
<input name="username" type="text"></input>
<input name="password" type="text"></input>
<input name="continue" type="button"></input>
<input name="cancel" type="button"></input>
<input value="SYS123456" name="vid" type="text">
<input value="ks10cf6d6" name="cid" type="text">
</form>
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
</div>
通过 CSS 语法进行匹配的实例:
locator | 匹配 |
---|---|
css=divcss、=div.formdiv | < div class=“formdiv”> |
css=#recordlist、css=ul#recordlist | < ul id=“recordlist”> |
css=div.subdiv p、css=div.subdiv > ul > p | < p>Heading< /p> |
css=form + div | < div class=“subdiv”> |
css=p + li、css=p ~ li | 二者定位到的都是 < li>Cat< /li>但是 storeCssCount 的时候,前者得到 1,后者得到 4 |
css=form > input[name=username] | < input name=“username”> |
css=input[name$=id][value^=SYS] | < input value=“SYS123456” name=“vid” type=“hidden”> |
css=input:not([name$=id][value^=SYS]) | < input name=“username” type=“text”>< /input> |
css=li:contains(‘Goa’) | < li>Goat< /li> |
css=li:not(contains(‘Goa’)) | < li>Cat< /li> |
结构性定位就是根据元素的父子、同级中位置来定位,css3标准中有定义一些结构性定位伪类如
nth-of-type,nth-child,但是使用起来语法很不好理解,这里就不做介绍了。
Selenium 中则是采用了来自 Sizzle 的 css3定位扩展,它的语法更加灵活易懂。
例如下面一段代码:
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
Sizzle Css3还提供一些直接选取 form 表单元素的伪类:
:input: Finds all input elements (includes textareas, selects, and buttons).
:text, :checkbox, :file, :password, :submit, :image, :reset, :button: Finds the input element
with the specified input type (:button also finds button elements).
下面是一些 XPATH 和 CSS 的类似定位功能比较(缺乏一定的严谨性)。
通过对比,我们可以看到,CSS 定位语法比 XPath 更为简洁,定位方式更多灵活多样;不过对 CSS 理
解起来要比 XPath 较难;但不管是从性能还是定位更复杂的元素上,CSS 优于 XPath,笔者更推荐使用 CSS定位页面元素。
关于自动化的定位问题
自动化测试的元素定位一直是困扰自动化测试新手的一个障碍,因为我们在自动化实施过程中会碰到
各式各样的对象元素。虽然 XPath 和 CSS 可以定位到复杂且比较难定位的元素,但相比较用 id 和 name 来说增加了维护成本和学习成本,相比较来说 id/name 的定位方式更直观和可维护,有新的成员加入的自动化时也增加了人员的学习成本。所以,测试人员在实施自动化测试时一定要做好沟通,规范前端开发人员对元素添加 id/name 属性,或者自己有修改 HTML 代码的权限
大家一起学习进步软件测试打卡交流社区←←←,每天都有直播教学哦