Web 端自动化测试

一.环境搭建

  • 准备工具如下:下载 python【python 开发环境】(http://python.org/getit/)
  • 下载setuptools: 【python 的基础包工具】(http://pypi.python.org/pypi/setuptools
  • 下载pip:【Python安装包管理工具】( https://pypi.python.org/pypi/pip)

 setuptools 是 python 的基础包工具,可以帮助我们轻松的下载,构建,安装,升级,卸载 python 的软件包

pip 是python软件包的安装和管理工具,有了这个工具,我们只需要一个命令就可以轻松的python 的任意类库。

windows环境安装:

第一步、安装 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 为:

第三步、安装 pip ,通过上面提供的链接下载 pip-1.4.1.tar.gz(版本随着时间版本会有更新),我默认解压在了 C:pip-1.4.1 目录下,打开命令提示符(开始--运行--cmd 命令,回

车)进入 C:pip-1.4.1目录下输入:

C:pip-1.4 41 .1 > > n python y setup.py install

再切换到 C:Python27Scripts 目录下输入:

C:Python27Scripts > > l easy_install

第四步、安装 selenium,如果是电脑处于联网状态的话,可以直接在 C:Python27Scripts 下输入命令安装

如果没联网,可以通过下载安装:
selenium 下载地址: https://pypi.python.org/pypi/selenium
下载 selenium 2.33.0 (目前的最新版本),并解压把整个目录放到 C:Python27Libsite-packages  目录下

第一个自动化脚本

# 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()

代码解析:
# 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 所这设置的目录下,如果前面已经将python添加到环境变量中,那么可以将驱动(chromedriver.exe)放到python 的安装目录下

安装完成后可以用 IE 和 chrome 来替换 firefox 运行上面的例子:

#用火狐打开
browser = webdriver.Firefox() #用IE打开 browser = webdriver.Ie() #用Chrome打开 browser = webdriver.Chrome()

如果程序能够调用相应的浏览器运行,说明浏览器驱动安装成功

OperaDriver 是WebDriver厂商OperaSoftware和志愿者开发了对于Opera的Webdriver实现,安装方式与IE,chrome,有所不同

python webdriver API

浏览器的操作:

浏览器的最大化:

在统一的浏览器大小下运行用例,可以比较容易的跟一些基于图像比对的工具进行结合,提升测试的灵活性及普遍适用性。

#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.junjie.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()

简单对象的定位:

对象(元素)的定位和操作时自动化测试的核心部分,其实操作又是建立在定位的基础上的,因此元素定位就显的非常重要

一个对象就像一个人,他会有各种的特征(属性)比如我们可以通过一个人的身份证号,姓名或者他的住址找到这个人,那个一个元素也有类似的属性,我们可以通过这种唯一区别于其他元素的属性来找到这个元素,当然,除了要操作元素时需要定好元素外,有时候我们为了获得元素的属性(class属性,name属性)text 或数量也需要定位元素

webdriver 提供了一系列的元素定位方法,常用的有以下几种

 id

 name

 class name

 tag name

 link text

 partial link text

 xpath

 css selector

分别对应python  webdriver 中的方法为“:

find_elemnent_by_id()

find_element_by_name()

find_element_by_class_name()

find_element_by_tag_name()

find_element_by_link_text()

find_element_by_partial_link_text()

find_element_by_xpath()

find_element_by_css_selector()

id和name定位:

id和name 是我们最常用的定位方式,因为大多元素中都有这两个属性,而且在对控件的id 和name 命名时一般使其有意义也会取不同的名字。通过这两个属性使我们找一个页面上的属性变得相当容易。

通过元素中所带的id和name属性来对元素进行定位

id=” gs_htif0 ”

find_element_by_id(" gs_htif0 ")

name=”btnK”

find_element_by_name("btnK")

 


find_element_by_name("btnI"

tag name 和 class  name定位

不是所有的前端人员都喜欢为每一个元素添加id和name 属性,但除此之外你一定发现了一个元素不单单只有id 和name 属性,他还有class 属性

通过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定位

有时候需要操作的元素是一个文字链接,那么我们可以通过link  text 或 partial link text 进行元素定位

通过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定位

XPath 是一种在XML 文档中定位元素的语言,因为HTML 可以看做XML 的一种实现,所以 selenium 用户可以使用这种强大语言在web 应用中定位元素

XPath 扩展上面id和name 定位方式,提供了很多种可能性,比如页面的第三个多选框

我们看到的是一个层级关系页面,下面我看看如果用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 的实现是不一样的

css定位

css 是一种语言,他被用来描述HTML 和XML 的文档表现,css 使用选择器来为页面元素绑定属性。这些选择器可以被selenium 用作另外的定位策略

css 可以比较灵活选择控件的任意属性,一般情况下定位速度要比XPath 快,

例如下面一段代码:

通过 CSS 语法进行匹配的实例:

css 中的结构性定位

结构性定位就是根据元素的父子、同级中位置来定位,css3标准中有定义一些结构性定位伪类如nth-of-type,nth-child,但是使用起来语法很不好理解,这里就不做介绍了

Selenium 中则是采用了来自 Sizzle 的 css3定位扩展,它的语法更加灵活易懂

Sizzle Css3的结构性定位语法:

例如下面一段代码:

 

操作页面对象

前面不少知识都是定位对象,定位只是第一步,定位之后需要对这个对象进行操作,鼠标点击呢还是键盘输入,这要取决于我们定位对象所支持的操作

一般来说,所有有趣的操作与页面交互都将通过WebElement接口,包括上一节中介绍的对象定位

webdriver 中比较常用的操作元素的方法有下面几个:

  • clear  :清除元素的内容
  • send_keys  :在元素上模拟按键输入
  • click  :单机元素
  • submit   :提交表单

 登陆实例:

#coding=utf-8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebclou
d.kuaibo.com%2F")
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys("password")
driver.find_element_by_id("dl_an_submit").click()
#通过 submit() 来提交操作
#driver.find_element_by_id("dl_an_submit").submit()
driver.quit()

WebElement 接口常用方法:

WebElement 接口除了我们前面介绍的方法外,它还包含了另外一些有用的方法,例如:

size

返回元素的尺寸:

#返回百度输入狂的宽高
size=driver.find_element_by_id("kw").size
print size

text

获取元素的文本:

text=driver.find_element_by_id("cp").text
print text

get_attribute(name)

获取属性值:

#返回元素的属性值,可以是 id、name、type 或元素拥有的其它任意属性
attribute=driver.find_element_by_id("kw").get_attribute('type')
print attribute

需要说明的是这个方法在定位一组时将变得非常有用,

is_displayed()

设置改元素是否用户可见

#返回元素的结果是否可见,返回结果为 True 或 False
result=driver.find_element_by_id("kw").is_displayed()
print result

WebElement 接口的其它更多方法请参考 webdriver API

 鼠标事件

有关鼠标的操作,不单单只有点击,有时候还要和右击,双击,拖动等操作,这些操作包含在ActionChains类中

ActionChains类鼠标操作的常用方法:

  • context_click( )右击
  • double_click()双击
  • drag_and_drop()  拖动
  • move_to_element() 鼠标悬停在一个元素上
  • click_and_hold() 按下鼠标左键在一个元素上
#引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
#定位到要右击的元素
right =driver.find_element_by_xpath("xx")
#对定位到的元素执行鼠标右键操作
ActionChains(driver).context_click(right).perform()
....

from selenium.webdriver.common.action_chains import ActionChains

这里需要注意的是,在使用 ActionChains 类下面的方法之前,要先将包引入。

ActionChains(driver)

driver: wedriver 实例执行用户操作。

ActionChains 用于生成用户的行为;所有的行为都存储在 actionchains 对象。通过 perform()执行

存储的行为。

perform()

执行所有 ActionChains 中存储的行为。perfrome()同样也是 ActionChains 类提供的的方法,通常与ActionChains()配合使用。

鼠标双击操作:(double_click(on_element))

#引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
#定位到要双击的元素
double =driver.find_element_by_xpath("xxx")
#对定位到的元素执行鼠标双击操作
ActionChains(driver).double_click(double).perform()

鼠标拖放操作:(drag_and_drop(source, target))

在元素上按下鼠标左键,然后移动到目标元素上释放

source  :鼠标按下的源元素

target: 鼠标释放的目标元素

#引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
#定位元素的原位置
element = driver.find_element_by_name("xxx")
#定位元素要移动到的目标位置
target = driver.find_element_by_name("xxx")

#执行元素的移动操作
ActionChains(driver).drag_and_drop(element, target).perform()

鼠标移动到元素上:

move_to_element()

#引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
#定位到鼠标移动到上面的元素
above = driver.find_element_by_xpath("xxx")
#对定位到的元素执行鼠标移动到上面的操作
ActionChains(driver).move_to_element(above).perform()

按下鼠标左键

click_and_hold()

按住鼠标左键在一个元素

#引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains
...
#定位到鼠标按下左键的元素
left=driver.find_element_by_xpath("xxx")
#对定位到的元素执行鼠标左键按下的操作
ActionChains(driver).click_and_hold(left).perform()

键盘事件

我们在实际的测试工作中,有时候我们在测试时需要使用 tab 键将焦点转移到下一个元素,用于验证元素的排序是否正确。webdriver 的 Keys()类提供键盘上所有按键的操作,甚至可以模拟一些组合建的操作,如 Ctrl+A ,Ctrl+C/Ctrl+V 等。在某些更复杂的情况下,还会出现使用 send_keys 来模拟上下键来操作下拉列表的情况。

#coding=utf-8
from selenium import webdriver
#引入 Keys 类包
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#输入框输入内容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)
#删除多输入的一个 m
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
time.sleep(3)
#输入空格键+“教程”
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys(u"教程")
time.sleep(3)
#ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
time.sleep(3)
#ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')
time.sleep(3)
#输入框重新输入内容,搜索
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'v')
time.sleep(3)
#通过回车键盘来代替点击操作
driver.find_element_by_id("su").send_keys(Keys.ENTER)
time.sleep(3)
driver.quit()

from selenium.webdriver.common.keys import Keys

在使用键盘按键方法前需要先导入 keys 类包。

下面经常使用到的键盘操作:

send_keys(Keys.BACK_SPACE) 删除键(BackSpace)

send_keys(Keys.SPACE) 空格键(Space)

send_keys(Keys.TAB) 制表键(Tab)

send_keys(Keys.ESCAPE) 回退键(Esc)

send_keys(Keys.ENTER) 回车键(Enter)

send_keys(Keys.CONTROL,'a') 全选(Ctrl+A)

send_keys(Keys.CONTROL,'c') 复制(Ctrl+C)

send_keys(Keys.CONTROL,'x') 剪切(Ctrl+X)

send_keys(Keys.CONTROL,'v') 粘贴(Ctrl+V)

打印信息

当我们要设计功能测试用例时,一般会有预期结果,有些预期结果是由测试人员同过肉眼进行判断,因为自动化的测试过程是无人值守,一般情况下,脚本运行成功,没有异样信息就标识用户执行成功,当然这还足够去正明一个用例确实是执行成功的。所以我们需要获得更多的信息来证明用例执行结果确实是成功的

通常我们可以通过获得页面的title  URL 地址,页面上的标识性信息(如:登陆成功,“欢迎XXX”)来判断用例执行成功

在实际测试中,访问一个页面判断其titlle 是否符合预期是一个很常见的用例,

获取当前URL也是非常重要的一个操作,在某些情况下,你访问一个URL ,这时系统会自动对这个URL 进行跳转,这就是所谓的“重定向”  一般测试重定向的方法是访问这个URL,然后等待页面重定向完毕之后,获取当前页面的URL ,判断URL是否符合预期,如果页面的URL 返回不正确,而表示当前操作没有进行正常跳转

#coding=utf-8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud
.kuaibo.com%2F")
#登录
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys("password")
driver.find_element_by_id("dl_an_submit").click()
#获得前面 title,打印
title = driver.title
print title
#拿当前 URL 与预期 URL 做比较
if title == u"快播私有云":
print "title ok!"
else:
print "title on!"
#获得前面 URL,打印
now_url = driver.current_url
print now_url
#拿当前 URL 与预期 URL 做比较
if now_url == "http://webcloud.kuaibo.com/":
print "url ok!"
else:
print "url on!"
#获得登录成功的用户,打印
now_user=driver.find_element_by_xpath("//div[@id='Nav']/ul/li[4]/a[1]/span")
.text
print now_user
driver.quit()

上例中涉及到的新的方法如下:

title:返回页面的当前标题

current_url

获取当前价值页面的url

设置等待时间:

有时候为了保证脚本运行的稳定性,需要脚本中添加等待时间

sleep();设置固定的休眠时间,python  的time包提供了休眠方法sleep()  导入time 包后就可以使用sleep()

implicitly_wait() 是webdriver 提供的一个超时等待,隐的等待一个元素被发现,或一个命令被完成,如果超出了设置时间则抛出异常

WebDriverWait() :同样是webdriver 提供的方法,在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常

#coding=utf-8
from selenium import webdriver
#导入 WebDriverWait 包
from selenium.webdriver.support.ui import WebDriverWait
#导入 time 包
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#WebDriverWait()方法使用
element=WebDriverWait(driver, 10).until(lambda driver :
driver.find_element_by_id("kw"))
element.send_keys("selenium")
#添加智能等待
driver.implicitly_wait(30)
driver.find_element_by_id("su").click()
#添加固定休眠时间
time.sleep(5)
driver.quit()

sleep()

sleep()方法以秒为单位,假如休眠时间小于一秒,可以用小数点表示

implicitly_wait() 

implicitly_wait() 方法比sleep ()更加智能,后者只能选择一个固定的时间等待

WebDriverWait()

详细格式如下:

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)

driver - WebDriver 的驱动程序(Ie, Firefox, Chrome 或远程)

timeout - 最长超时时间,默认以秒为单位

poll_frequency - 休眠时间的间隔(步长)时间,默认为 0.5 秒

ignored_exceptions 超时后的异常信息,默认情况下抛 NoSuchElementException 异常

from selenium.webdriver.support.ui import WebDriverWait
....
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id(“someId”))
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).
until_not(lambda x: x.find_element_by_id(“someId”).is_displayed())

WebDriverWai()一般由 unit()或 until_not()方法配合使用,下面是 unit()和 until_not()方法的说明。

until(method, message=’’):调用该方法提供的驱动程序作为一个参数,直到返回值不为 False

until_not(method, message=’’)  调用该方法提供的驱动程序作为一个参数,直到返回值为 False。

定位一组对象

webdriver 可以很方便的使用 find_element 方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,WebElement 接口同样提供了定位一组元素的方法 find_elements。

定位一组对象的场景:

  • 批量操作对象,比如将页面上的多选框都选上

先获取一组对象,再在对象中过滤出需要具体定位的一些对象,,比如定位页面上所有的checkbox  然后选择最后一个

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
<script type="text/javascript" async="
" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet" />
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
</form>
</div>
</body>
</html>

将这段代码保存复制到记事本中,将保存成 checkbox.html 文件。(注意,这个页面需要和我们的自动
化脚本放在同一个目录下,否则下面的脚本将指定 checkbox.html 的所在目录)
通过浏览器打开 checkbox.html,将看到以下页面

通过图 3.4 可以看到页面提供了三个复选框和两个单选按钮。下面通过脚本来单击勾选三个复选框

# -*- coding: utf-8 -*-
from selenium import webdriver
import os
driver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('checkbox.html')
driver.get(file_path)
# 选择页面上所有的 tag name 为 input 的元素
inputs = driver.find_elements_by_tag_name('input')
#然后从中过滤出 tpye 为 checkbox 的元素,单击勾选
for input in inputs:
if input.get_attribute('type') == 'checkbox':
input.click()
driver.quit()

import os

os.path.abspath()

os 模块为 python 语言标准库中的 os 模块包含普遍的操作系统功能。主要用于操作本地目录文件。

path.abspath()方法用于获取当前路径下的文件。另外脚本中还使用到 for 循环,对 inputs 获取的一组元素进行循环,在 python 语言中循环变量(input)可以不用事先声明直接使用

find_elements_by_xx(‘xx’)

find_elements 用于获取一组元素。

下面通过 css 方式来勾选一组元素,打印当所勾选元素的个数并对最后一个勾选的元素取消勾选

#coding=utf-8
from selenium import webdriver
import os
driveriver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('checkbox.html')
driver.get(file_path)
# 选择所有的 type 为 checkbox 的元素并单击勾选
checkboxes = driver.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
checkbox.click()
# 打印当前页面上 type 为 checkbox 的个数
print len(driver.find_elements_by_css_selector('input[type=checkbox]'))
# 把页面上最后1个 checkbox 的勾给去掉
driver.find_elements_by_css_selector('input[type=checkbox]').pop().click()
driver.quit()

len() :len为python 语言中的方法,用于返回对象的长度(或个数)

pop() :pop 也为python 语言中提供的方法,用于删除指定位置的元素,pop ()为空默认选择最后一个元素

层级定位:

在实际的项目测试中,经常会有这样的需求,页面上有很多个属性基本相同的元素,现在需要具体的定位到其中的一个,由于属性基本相当,所以在定位的时候会比较麻烦,这时候就需要用到层级定位,先定位到父元素,然后再通过父元素定位到子孙元素

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Level Locate</title>
<script type="text/javascript" async="
" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet" />
</head>
<body>
<h3>Level locate</h3>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link1</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" id="dropdown1" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link2</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>

将上面的代码保存为 level_locate.html,通过浏览器打开将看到以下页面

 通过对上面代码的分析,发现两个下拉菜单中每个选项的 link text 都相同,href 也一样,所以在这里就需要使用层级定位了

 具体思路是:先点击显示出一个下拉菜单,然后再定位到该下拉菜单所在的ul  ,在定位这个ul 下的某个具体的link,在这里,我们定位第 1 个下拉菜单中的 Another action 这个选项

#coding=utf-8
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
import time
import os
driver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('level_locate.html')
driver.get(file_path)
#点击 Link1 链接(弹出下拉列表)
driver.find_element_by_link_text('Link1').click()
#在父亲元件下找到 link 为 Action 的子元素
menu =
driver.find_element_by_id('dropdown1').find_element_by_link_text('Another
action')
#鼠标移动到子元素上
ActionChains(driver).move_to_element(menu).perform()
time.sleep(5)
driver.quit()

driver.find_element_by_id('xx').find_element_by_link_text('xx').click()

 这里用到了二次定位,通过对 Link1 的单击之后,出现下拉菜单,先定位到下拉菜单,再定位下拉菜,单中的选项。当然,如果菜单选项需要单击,可通过二次定位后也直接跟 click()操作。

 ActionChains(driver)

driver: wedriver 实例执行用户操作

ActionChains 用于生成用户的行为,所有的行为都存储在 actionchains 对象。通过 perform()执行存储的行为

move_to_element(menu)

 move_to_element 方法模式鼠标移动到一个元素上,上面的例子中 menu 已经定义了他所指向的是哪一个元素

perform()

 执行所有 ActionChains 中存储的行为

定位frame 中的对象

在 web 应用中经常会出现 frame 嵌套的应用,假设页面上有 A、B 两个 frame,其中 B 在 A 内,那么定位 B 中的内容则需要先到 A,然后再到 B

switch_to_frame 方法可以把当前定位的主体切换了 frame 里。怎么理解这句话呢?我们可以从 frame的实质去理解。frame 中实际上是嵌入了另一个页面,而 webdriver 每次只能在一个页面识别,因此才需要用 switch_to.frame 方法去获取 frame 中嵌入的页面,对那个页面里的元素进行定位

下面的代码中 frame.html 里有个 id 为 f1 的 frame,而 f1 中又嵌入了 id 为 f2 的 frame,该 frame 加载了百度的首页

frame.html

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>frame</title>
<script type="text/javascript" async="
"src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet" />
<script type="text/javascript">$(document).ready(function(){
});
</script>
</head>
<body>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" src="inner.html" width="800" height="600"></iframe>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>

inner.html

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="http://www.baidu.com" width="700" height="400">
</iframe>
</div>
</div>
</body>
</html>

frame.html 中嵌套 inner.html ,两个文件和我们的脚本文件放同一个目录下,通过浏览器打开,得到下列页面:

下面通过 switch_to_frame 方法来定位 frame 内的元素

#coding=utf-8
from selenium import webdriver
import time
import os
driver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('frame.html')
driver.get(file_path)
driver.implicitly_wait(30)
#先找到到 ifrome1(id = f1)
driver.switch_to_frame("f1")
#再找到其下面的 ifrome2(id =f2)
driver.switch_to_frame("f2")
#下面就可以正常的操作元素了
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(3)
driver.quit()

switch_to_frame 的参数问题。官方说 name 是可以的,但是经过实验发现 id 也可以。所以只要 frame中 id 和 name,那么处理起来是比较容易的。如果 frame 没有这两个属性的话,你可以直接手动添加

 对话框处理

页面上弹出的对话框是自动化测试经常会遇到的一个问题,很多情况下对话框是一个 iframe,如上一节中介绍的例子,处理起来稍微有点麻烦;但现在很多前端框架的对话框是 div 形式的,这就让我们的处理变得十分简单

为百度首页的登录对话框,下面通过脚本对百度进行登录操作:

#coding=utf-8
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://www.baidu.com/")
#点击登录链接
driver.find_element_by_name("tj_login").click()
#通过二次定位找到用户名输入框
div=driver.find_element_by_class_name("tang-content").find_element_by_name("userName")
div.send_keys("username")
#输入登录密码
driver.find_element_by_name("password").send_keys("password")
#点击登录
driver.find_element_by_id("TANGRAM__PSP_10__submit").click()
driver.quit()

本例中并没有用到新方法,唯一的技巧是用到了二次定位,这个技巧在层级定位中已经有过使用

driver.find_element_by_class_name("tang-content").find_element_by_name("userName")

第一次定位找到弹出的登录框,在登录框上再次进行定位找到了用户名输入框

 浏览器多窗口处理

有时候我们在测试一个 web 应用时会出现多个浏览器窗口的情况,在 selenium1.0 中这个问题比较难处理。webdriver 提供了相关相方法可以很轻松的在多个窗口之间切换并操作不同窗口上的元素

要想在多个窗口之间切换,首先要获得每一个窗口的唯一标识符号(句柄)。通过获得的句柄来区别分不同的窗口,从而对不同窗口上的元素进行操作

#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com/")
#获得当前窗口
nowhandle=driver.current_window_handle
#打开注册新窗口
driver.find_element_by_name("tj_reg").click()
#获得所有窗口
allhandles=driver.window_handles
#循环判断窗口是否为当前窗口
for handle in allhandles:
if handle != nowhandle:
driver.switch_to_window(handle)
print 'now register window!'
#切换到邮箱注册标签
driver.find_element_by_id("mailRegTab").click()
time.sleep(5)
driver.close()
#回到原先的窗口
driver.switch_to_window(nowhandle)
driver.find_element_by_id("kw").send_keys(u"注册成功!")
time.sleep(3)
driver.quit()

处理过程:

这个处理过程相比我们前面的元素操作来说稍微复杂一些,执行过程为:首选通过 nowhandle 获得当前窗口(百度首页)的句柄;然后,打开注册窗口(注册页);通过 allhandles 获得所有窗口的句柄;对所有句柄进行循环遍历;判断窗口是否为 nowhandle(百度首页),如果不是则获得当前窗口(注册页)的句柄;然后,对注册页上的元素进行操作。最后,回返到首页

为了使执行过程更多更容易理解,在切换到注册页时,打印了'now register window!'一条信息;切换回百度首页时,我们在输入框输入了“注册成功!”。注意,我们在切换到注册页时,只是切换了一下邮箱注册标签,如果要直执行注册过程还需要添加更多的操作步骤。

  • 在本例中所有用到的新方法:
  • current_window_handle(获得当前窗口句柄)
  • window_handles(返回的所有窗口的句柄到当前会话)
  • switch_to_window(用于处理多窗口操作的方法,与我们前面学过的 switch_to_frame() 是类似,switch_to_window()用于处理多窗口之前切换,switch_to_frame() 用于处理多框架的切换。)
  • close():如果你足够细心会发现我们在关闭“注册页”时用的是 close()方法,而非 quit();close()用于关闭当前窗口,quit()用于退出驱动程序并关闭所有相关窗口。



原文地址:https://www.cnblogs.com/zhang-jun-jie/p/9311049.html