selenium数据驱动

数据驱动应该是自动化的一个进步;从它的本意来讲,数据的改变(更新)驱动自动化的执行,从而
引起测试结果的改变。这显然是一个非常“高级”的概念和想法。其实,我们可以直白的理解成参数化,
输入数据的不同从而引起输出结果的变化。

不管我们读取的是数组、字典,又或者是excel/csv、txt 文件。我们实现了数据与脚本的分离,换
句话说,我们实现了参数化。对于同段脚本来说,由于我们传输入了100 条数据,那么会真对这100 条数
据返回对应的100 结果。
同样的脚本执行不同的数据从而得到了不同的结果,这样是不是增强的脚本的复用性呢!?
其实,模块化与参数化这对开发来说是完全没有什么技术含量的;对于当初QTP 自动化工具来说地确
是一个卖点,因为它面对的大多是不懂开发的测试,当然,随着时代的发展,懂开发的测试人员越来越多。 

数据驱动实例

1、126 邮箱登录
我们同样有以126 邮箱的登录为例了,现在我们的需求是测试登录。那么在测试登录的用例中我们需
求通过不同的用户名与密码进行验证。对于测试脚本来说,不变的是登录的步骤,变化的是每次所输入的
用户名和密码不同,这种情况下就需求用到数据驱动方式来完成这个需求。mail126.py

from selenium import webdriver
driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.get("http://www.126.com")
class Account(object):
"""docstring for Account"""
def __init__(self,username ='', password = ''):
self.username = username
self.password = password
def do_login_as(user_info):
driver.find_element_by_id("idInput").clear()
driver.find_element_by_id("idInput").send_keys(user_info.username)
driver.find_element_by_id("pwdInput").clear()
driver.find_element_by_id("pwdInput").send_keys(user_info.password)
driver.find_element_by_id("loginBtn").click()
#实例化登陆信息
admin = Account(username='admin',password='123')
guset = Account(username='guset',password='321')
#调用登陆函数
do_login_as(admin)
do_login_as(guset)

 首先创建表Account 类,对用户名密码进行初始化设置,紧接着创建do_login_as()函数用于实现用
户的登录操作,它需要一个user_info 参数用于接收用户的登录信息。取user_info 中的username 输入
到用户名输入框,取user_info 中的password 输入密码输入框。
紧接着下面的操作就是通过调用Account 实例化用户admin 和guset,进行个性化的参数设置。最后
分别调用do_login_as()函数来实现不同用户的登录。

2、百度搜索

如果126 邮箱登录的例子对于理解数据驱动概念不够清晰,那么我们再看一个百度搜索的例子,对于
这个例子前面已经出现过多次。我们每个上网的人每天都要用很多次百度,那么我们每一次使用的步骤都
是一样的,不一样的是每一次搜索的“关键字”不同,从而会得到不同的搜索结果。baidu.py

info.txt
selenium
webdriver
Python

创建info.txt 文件,每一行写上需要搜索的“关键字”。

#coding=utf-8
from selenium import webdriver
file_info = open('info.txt','r')
values = file_info.readlines()
file_info.close()
for serch in values:
driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
driver.find_element_by_id('kw').send_keys(serch)
driver.find_element_by_id('su').click()
driver.quit()

首先通过open()方法以读(‘r’)的方式打开当前目录下的info.txt 文件,通过readlines()获取
文件中所有行的数据,并赋值给变量values。通过close()关闭文件。
接下来的步骤就是循环的执行百度搜索的脚本,每一次取vlaues 中的一行数据做为“搜索关键字”
传递给百度输入框。通过这个例子更充分的体现有数据驱动的概念。

3、读取txt 文件

上面的例子中我们已经使用到了txt 文件的读取。Python 提供了以下几种读取文件的方式。

  •  read() 读取整个文件。
  •  readline() 读取一行数据。
  •  readlines() 读取所有行的数据。

readlines()方法我们通过上面的列子已经了解了它使用,那么问题来了,现在有一个新需求第次读取一个用户名和一个密码,上面所提供的几个读取文件数据的方法并不能解决这个需求。这个需求如何通过读取txt 文件实现呢?看下面的例子。

user_info.txt
zhangsan,123
lisi,456
wangwu,789

首先在数据的存放上做了调整,每一行存放用户名和密码,它们之间用逗号隔开。user_info.txt

#coding=utf-8
from selenium import webdriver
user_file = open('user_info.txt','r')
values = user_file.readlines()
user_file.close()
for serch in values:
username = serch.split(',')[0]
print username
password = serch.split(',')[1]
print password

运行结果:
>>> ========================= RESTART ==============================
>>> zhangsan
123
lisi
456
wangwu
678 

在读取user_info.txt 文件的时候,同样使用readlines()方法读取所有行的数据,那么获取到的一
行数据如何拆分出用户名和密码是关键,这里我们使用split()进行拆分,它可将一个字符符串通过某一
符号拆分成左右两部分,这里逗号(,)为分割点。split()拆分出来的左右两部分以数据的形式存放,
所用[0]可以取到左半部分的字符串,[1]可以取到右半部分的字符串。
这样就可以方便有使用txt 文件来存放用户名和密码数据了,或者其它必须成对调用的数据。

4、读取csv 文件

那么新的问题来了,假如,现在要读取的是一组用户数据,这一组数据包括用户名、邮箱、年龄、性别等信息。这个时候再使用aplit()方法拆分就可不那么方便了,因为它一次只能将字符串拆分成左右两部分。
下面通过读取csv 文件的方法来解决这个每次要读取多个信息的问题。首先创建userinfo.csv 文件,通过WPS 表格或Excel 创建表格,文件另存为选择CSV 格式进行保存,注意不要直接修改Excel 的后缀名来创建CSV 文件,这样创建出来的并非真正的CSV 文件。

下面修改loop_reader.py 文件进行循环读取:user_info.txt

#coding=utf-8
import csv #导入csv 包
#读取本地CSV 文件
my_file='info.csv'
date=csv.reader(file(my_file,'rb'))
#循环输出每一行信息
for user in date:
print user

 运行结果:
>>> ========================= RESTART ==============================
>>>
['testing', '123456@126.com', '23', 'man']
['testing2', '123456@qq.com', '18', 'woman']
['testing3', '123456@128.com', '29', 'woman']

首先表导入csv 模块,通过reader()方法读取csv 文件。然后通过for 循环遍历文件中的每一行数据。从打印结果可以看出是以数组的形式存的。那么如果想取用户的某一列信息,只需要指定下标即可。user_info.txt

#coding=utf-8
import csv
my_file='info.csv'
date=csv.reader(file(my_file,'rb'))
#取用户的邮箱地址
for user in date:
print user[1]

运行结果:
>>> ========================= RESTART ==============================
>>>
123456@126.com
123456@qq.com
123456@128.com
在上面的例子中只需要取所有用户的邮箱地址,那么只需要指定邮箱地址的所在例即可。数组下标是
以0 开始的,取第二例的信息下标为1。
通过这种方式就解决读取多列数据的问题,在本中是以读取CSV 文件为例,读取Excel 文件的方式也
类似,只是所调用的模块就需要从csv 切换为xlrd,真对Excel 文件操作的方法也有所不同。

4、读取xml 文件

在时间我们所需要读取的文件并有固定的行和例,而是一些不规则的配置信息,例如我们需要一个配
置文件来配置当前自动化测试脚本的URL、浏览器、登录用户名/密码等。这个时候可以选择XML 文件来配
置这些信息。
什么是XML?
XML 即可扩展标记语言,它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进
行定义的源语言。
xml 有如下特征:
首先,它是有标签对组成:<aa></aa>
标签可以有属性: <aa id=’123’></aa>
标签对可以嵌入数据: <aa>abc</aa>

标签可以嵌入子标签(具有层级关系):
<aa>
         <bb></bb>
</aa>
下面以读取info.xml 文件为例介绍读取XML 文件的方法。info.xml

获得标签信息read_xml.py

#coding=utf-8
import xml.dom.minidom
#打开xml 文档
dom = xml.dom.minidom.parse('info.xml')
#得到文档元素对象
root = dom.documentElement
print root.nodeName
print root.nodeValue
print root.nodeType
print root.ELEMENT_NODE

运行结果:
>>> ========================= RESTART ==============================
《Selenium2 Python 自动化测试实战》样张
128
>>>
catalog
None
1
mxl.dom.minidom
mxl.dom.minidom 模块被用来处理xml 文件,所以要先引入。
parse()
xml.dom.minidom.parse() 用于打开一个xml 文件,并将这个文件对象dom 变量。
documentElement
documentElement 用于得到dom 对象的文档元素,并把获得的对象给root
每一个结点都有它的nodeName,nodeValue,nodeType 属性。
nodeName 为结点名字。
nodeValue 是结点的值,只对文本结点有效。
nodeType 是结点的类型。

获得任意标签名read_xml.py

#coding=utf-8
import xml.dom.minidom
#打开xml 文档
dom = xml.dom.minidom.parse('info.xml')
#得到文档元素对象
root = dom.documentElement
tagname = root.getElementsByTagName('maxid')
print tagname[0].tagName
tagname = root.getElementsByTagName('caption')
print tagname[2].tagName
tagname = root.getElementsByTagName('item')
print tagname[1].tagName

运行结果:
>>> ========================= RESTART ==============================
>>>
maxid
caption
item
getElementByTagName()可以通过标签名获取某个标签。它所获取的对象是以数组形式存放。如
“caption”和“item”标签在info.xml 文件中有多个,那么可以指定数组的下标在获取某个标签。
root.getElementsByTagName('caption') 获得的是标签为caption 一组标签;
tagname[0] 表示一组标签中的第一个。
tagname[2] 表示一组标签中的第三个。

获得标签的属性值read_xml.py

#coding=utf-8
import xml.dom.minidom
#打开xml 文档
dom = xml.dom.minidom.parse('info.xml')
#得到文档元素对象
root = dom.documentElement
logins = root.getElementsByTagName('login')
#获得login 标签的username 属性值
username=logins[0].getAttribute("username")
print username
#获得login 标签的passwd 属性值
password=logins[0].getAttribute("passwd")
print password
items = root.getElementsByTagName('item')
#获得第一个item 标签有id 属性值
id1=items[0].getAttribute("id")
print id1
#获得第二个item 标签有id 属性值
id2=items[1].getAttribute("id")
130
print id2

运行结果:
>>> ========================= RESTART ==============================
>>>
pytest
123456
42
getAttribute()
getAttribute()方法可以获得元素的属性所对应的值。

获得标签对之间的数据read_xml.py

#coding=utf-8
import xml.dom.minidom
#打开xml 文档
dom = xml.dom.minidom.parse('info.xml')
#得到文档元素对象
root = dom.documentElement
captions=dom.getElementsByTagName('caption')
#获得第一个标签对的值
c1=captions[0].firstChild.data
print c1
#获得第二个标签对的值
c2=captions[1].firstChild.data
print c2
#获得第三个标签对的值
c3=captions[2].firstChild.data
print c3

运行结果:
>>> ========================= RESTART ==============================
>>>

test
Zope
firstChild.data
firstChild 属性返回被选节点的第一个子节点,data 表示获取该节点的数据。

小结:
在本章的学习中,我们首先介绍了几种自动化测试模型,然后通过实例介绍了模块化的应用。在数据
驱动的小节里,分别介绍了txt、csv 和xml 三种文件的读取,读者可以根据需求选择这三种文件来存放
数据。
模块化和数据驱动在脚本开发过程是必不可少的两个知识点,这也是开发出可复用和可维护的脚本的
基础,希望读者灵活运行。
当然,除了前面介绍的几种测试模型外,Page Object Model 也是逐渐流行起来的一种设计模式。我
们将在后面的章节中重点讨论这种设计模式。

展开阅读全文

没有更多推荐了,返回首页