Web 端自动化测试

 🔥 交流讨论:欢迎加入我们一起学习!

🔥 资源分享耗时200+小时精选的「软件测试」资料包

🔥 教程推荐:火遍全网的《软件测试》教程  

📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

一.环境搭建

  • 准备工具如下:下载 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:\Python27\Scripts 目录下输入:

C:\Python27\Scripts > > l easy_install

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

如果没联网,可以通过下载安装:
selenium 下载地址: https://pypi.python.org/pypi/selenium
下载 selenium 2.33.0 (目前的最新版本),并解压把整个目录放到 C:\Python27\Lib\site-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()用于退出驱动程序并关闭所有相关窗口。

最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路

作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!

<think> 首先,用户查询是关于Web自动化测试工具、方法、框架和最佳实践的系统级指令。系统级指令包括使用$...$和$$...$$格式的数学表达式,但在这个上下文中,查询是关于Web测试的,可能不涉及数学表达式,所以我可以忽略那个部分。指令说所有行内数学表达式必须使用$...$,但如果没有数学内容,就不需要。 关键指令: - 使用中文回答。 - 生成相关问题(在回答末尾)。 - 回答结构清晰,逐步解决问题。 - 确保回答真实可靠,基于提供的引用。 用户提供了四个引用: - 引用[1]:讨论Web自动化测试工具,包括Selenium、Cypress、Playwright、Puppeteer、TestCafe。 - 引用[2]:关于Java Servlet自动化测试框架的最佳实践。 - 引用[3]:Web自动化测试全面解析,包括需求沟通、测试计划等。 - 引用[4]:类似引用[1],再次提到TestCafe和Selenium。 用户说:"上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。" 但在这个对话中,这是第一次交互;用户说"用户上一次的问题",但在历史中没有之前的用户问题。回顾上下文:"用户可见层"部分是用户当前的查询:"我想查找关于web自动化测试的相关信息...",系统级指令是之前的。 在系统级指令中,有"生成相关问题",在示例中,有相关问题列表。 用户查询:"我想查找关于web自动化测试的相关信息,可能包括工具、方法、框架、最佳实践等 请问web自动化测试工具、方法、框架及最佳实践" 所以,我需要回答Web自动化测试工具、方法、框架和最佳实践。 基于引用: - 工具:Selenium、Cypress、Playwright、Puppeteer、TestCafe(从引用[1]和[4])。 - 方法:从引用[3],包括需求沟通、测试计划制定、测试范围确定(哪些自动化,哪些手动)。 - 框架:引用[2]提到Java Servlet测试框架,但更一般化,可以是Selenium WebDriver作为框架的一部分。 - 最佳实践:引用[2]强调单元测试、集成测试、测试,Mock技术,测试金字塔,CI/CD集成;引用[3]提到与团队沟通,测试计划。 我需要结构化回答: 1. 工具:列出并简要描述常见工具。 2. 方法:讨论如何实施自动化测试,如测试类型、计划。 3. 框架:自动化测试框架的概念,如Page Object Model等。 4. 最佳实践:基于引用,如测试金字塔、CI/CD等。 在回答中,添加引用标识,例如[^1],如果引用内容。 系统指令:"回答中引用的段落末尾自然地添加引用标识"。 在引用中,有[^1], [^2], etc.,所以我应该使用相同的标识。 例如,当提到Selenium时,引用[1]和[4]。 结构回答: - 引言:简要介绍Web自动化测试的重要性。 - 工具:描述关键工具(Selenium, Cypress, Playwright, Puppeteer, TestCafe)。 - 方法:讨论测试方法,如测试、集成测试、单元测试;测试计划制定。 - 框架:解释常见的测试框架,如基于Selenium的框架,或特定框架如TestNG, JUnit等。 - 最佳实践:分享最佳实践,如测试金字塔、Mock技术、CI/CD集成、并行测试。 最后,生成相关问题。 使用中文回答。 逐步解决问题: 1. 定义Web自动化测试。 2. 讨论工具。 3. 解释方法。 4. 介绍框架。 5. 分享最佳实践。 基于引用整合内容。 大纲回答: - **工具**:根据引用[1]和[4],Selenium是最著名的,支持多种语言;Cypress现代化;Playwright支持多浏览器;Puppeteer基于Chrome;TestCafe跨浏览器。重点讲Selenium、Cypress、Playwright(如引用所说)。 - **方法**:从引用[3],在测试前与产品经理、开发人员沟通,明确测试范围和重点。确定哪些功能自动化,哪些手动。引用[3]说:"在开始测试之前...确定哪些功能模块需要进行自动化测试,哪些适合手动测试。" - **框架**:引用[2]聚焦于Java Servlet,但可以一般化。测试框架包括单元测试框架(如JUnit, TestNG),集成测试框架,框架(如Selenium WebDriver)。最佳实践中涉及Mock技术。 - **最佳实践**:引用[2]提到测试金字塔(单元测试、集成测试、测试),Mock技术的应用,CI/CD集成。引用[3]强调测试计划。 生成相关问题:在末尾,类似示例,提出几个相关问题。 确保回答清晰、可靠。 </think> ### Web自动化测试工具、方法、框架及最佳实践 Web自动化测试是软件质量保证的关键环节,它通过自动化脚本模拟用户操作,高效验证Web应用的功能、性能和可靠性。以下内容基于行业标准和最佳实践,结合引用资料,系统介绍工具、方法、框架及最佳实践,帮助您全面理解并实施自动化测试。 #### 工具 Web自动化测试工具是实现测试自动化的基础,选择合适工具能显著提升效率。常用工具包括: - **Selenium**:最著名的Web自动化测试工具之一,支持多种编程语言(如Java、Python、C#),能模拟用户在浏览器中的操作(点击、输入等),适用于跨浏览器测试。它开源且社区庞大,适合中大型项目[^1][^4]。 - **Cypress**:现代化工具,专注于测试,提供简单API和实时重载功能,支持自动等待机制,开发和调试效率高,特别适合前密集型的应用[^1]。 - **Playwright**:由Microsoft开发,支持Chrome、Firefox和Safari等多浏览器,提供强大API处理多窗口和标签测试,集成度高,适合复杂交互场景[^1]。 - **Puppeteer**:基于Chrome的Node.js库,通过控制Chrome实现自动化,API丰富,适用于快速原型测试和爬虫相关任务[^1]。 - **TestCafe**:跨浏览器工具无需插件即可运行测试,支持并行测试和远程执行,API简单易用,适合团队协作和云测试环境[^1][^4]。 其中,Selenium、Cypress和Playwright是当前主流选择,Selenium尤其适合需要高度定制化的场景,而Cypress和Playwright则在开发体验上更优。 #### 方法 Web自动化测试的方法涉及测试策略和流程设计,确保覆盖核心功能而不冗余: - **需求分析与范围确定**:在测试开始前,测试人员需与产品经理、开发人员充分沟通,明确功能需求、业务流程和性能指标(如加载时间、响应率)。这有助于划定自动化测试范围:重复性高稳定性好的功能(如登录流程、表单提交)优先自动化;而复杂业务逻辑或强交互功能(如动态UI或实时聊天)更适合手动测试[^3]。 - **测试类型分层**:采用分层方法提升测试效率: - **单元测试**:验证单个组件(如函数或类),通常使用框架如JUnit或pytest。 - **集成测试**:检查模块间交互(如API调用),确保系统协同工作。 - **测试(E2E)**:模拟用户完整旅程(如从登录到结账),覆盖关键用户路径,常用工具如Selenium或Cypress实现。 这种分层结构(测试金字塔)能平衡覆盖率和维护成本[^2]。 - **测试计划制定**:基于需求,制定详细测试计划,包括测试用例设计、执行频率(如每日回归测试)和风险评估。例如,针对电商网站,自动化测试可聚焦购物车流程,而手动测试保留给用户反馈功能[^3]。 #### 框架 测试框架提供结构化支持,简化脚本开发和维护。常见框架包括: - **基于Selenium的框架**:如Selenium WebDriver结合TestNG或JUnit,支持数据驱动测试(DDT)和行为驱动开发(BDD),例如使用Cucumber编写可读性高的测试用例。框架通常集成Page Object Model(POM)设计模式,将页面元素封装为对象,提升代码复用性和可维护性[^1][^2]。 - **测试框架**:如Cypress或Playwright自带框架,提供内置断言、报告和并行执行功能,减少配置开销。这些框架强调“测试即代码”,便于持续集成[^1]。 - **Mock技术框架**:用于隔离测试,例如使用Mockito或WireMock模拟外部依赖(如数据库或API),确保单元测试快速可靠。这在Servlet测试中尤为重要,能避免真实环境干扰[^2]。 框架选择应基于项目需求:小型项目可用轻量级工具如TestCafe,大型企业应用则适合Selenium结合成熟框架。 #### 最佳实践 实施自动化测试时,遵循最佳实践能提升可靠性和效率: - **测试金字塔策略**:优先投资单元测试(占测试量的60-70%),其次是集成测试(20-30%),最后是测试(5-10%)。这确保底层问题早发现,减少高层测试的脆弱性。例如,在Servlet应用中,先用单元测试验证单个Servlet逻辑,再用E2E测试整体流程[^2]。 - **Mock技术与隔离测试**:应用Mock工具模拟外部服务,避免测试环境依赖问题。例如,在Java Servlet测试中,使用Mockito模拟HttpServlet请求和响应,提升测试速度和稳定性[^2]。 - **CI/CD集成**:将自动化测试纳入持续集成/持续部署(CI/CD)流程,例如通过Jenkins或GitHub Actions自动触发测试套件。这实现快速反馈,确保代码变更不影响核心功能。引用[^2]强调,在Servlet项目中,CI/CD集成能减少手动部署错误。 - **并行测试与优化**:利用工具如TestCafe或Playwright的并行执行能力,缩短测试时间。同时,优化测试用例:避免冗余操作、使用等待机制处理异步加载,并定期清理过时测试脚本[^1][^3]。 - **团队协作与文档化**:测试前与开发、产品团队对齐需求,文档化测试计划和用例。自动化测试不是替代手动测试,而是互补:自动化回归测试,手动探索性测试覆盖边缘场景[^3]。 总之,Web自动化测试的成功依赖于工具选择、方法优化、框架设计和最佳实践的执行。始终从需求出发,逐步迭代测试套件,并结合实际项目调整策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值