随笔记录方便自己和同路人查阅。
#------------------------------------------------我是可耻的分割线-------------------------------------------
学习selenium自动化之前,最好先学习HTML、CSS、JavaScript等知识,有助于理解定位及操作元素的原理。关于python和selenium安装请自行搜索别的资料,这里就不多做介绍了,所有例子均使用python3.6+selenium执行的。
#------------------------------------------------我是可耻的分割线-------------------------------------------
数据驱动测试实例
前面提到关于数据驱动的形式有很多,我们既可以通过定义变量的方式进行参数化,也可以通过定义数组、字典的方式进行参数化,还可以通过读取文件(txtcsv]xml)的方式进行参数化,我们通过一些例子来展示数据驱动在自动化测试中的应用。
参数化邮箱登录
同样以126邮箱的登入为例,现在的需求是测试不同用户的登录。对于测试用例来说,不变的是登录的步骤,变化的是每次登录的用户名和密码,这种轻卡下就需要用到数据驱动方式来编写测试用例。新建public.py文件
class Login(): def user_login(self,driver,username,password): #登录 driver.find_element_by_id('idInput').clear() driver.find_element_by_id('idInput').send_keys(username) driver.find_element_by_id('pwdInput').clear() driver.find_element_by_id('pwdInput').send_keys(password) driver.find_element_by_id('loginBtn').click() def user_logout(self,driver): driver.find_element_by_link_text('退出').click() driver.quit()
在user_login()方法中增加username、password的入参,将得到的具体参数作为登录时的数据。
新建mailTest.py文件
from selenium import webdriver from public import Login class LoginTest(): def __init__(self): driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get("http://www.126.com") #admin用户登录 def test_admin_login(self): username = 'admin' password = '123' Login().user_login(self.driver,username,password) self.driver.quit() #guest用户登录 def test_guest_login(self): username = 'guest' password = '321' Login().user_login(self.driver, username, password) self.driver.quit() LoginTest().test_admin_login() LoginTest().test_guest_login()
创建LoginTest()类,并在__init__()方法中初始化浏览器驱动、等待超时长和URL等。这样test_admin_login()与test_guest_login()两个测试方法只需关注登录的用户名和密码,通过调用Login()类的user_login()方法并传入具体的参数来测试不同用户的登录。
参数化搜索关键字
再来看一个百度搜索的例子。我们每天上网一般要很多次百度搜索,而我们每次在使用百度搜索时步骤都是一样的,不一样的时每次搜索的“关键字”不同。下面我们就以数组的方式对搜索的关键字进行参数化。
新建baidu.py
from selenium import webdriver serch_text = ['python','中文','text'] for text in serch_text: driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get('http://www.baidu.com') driver.find_element_by_id('kw').send_keys(text) driver.find_element_by_id('su').click() driver.quit()
这个例子比较简单,首先创建一个数组search_text用来存放搜索的关键字,通过for循环来便利数组,最后把便利的数组元素作为每次百度搜索的关键字。这个例子可以更充分地体现出数据驱动的概念:因为测试数据的不同从而引起测试结果的不同。
读取txt文件
Txt文件是我们经常操作的文件类型,python提供了一下几种读取txt文件的方式。
* read() 读取整个文件。
* readline() 读取一行数据。
* readlines() 读取所有行的数据。
回到前面登录的例子,现在使用txt文件来存放用户名和密码数据,并通过读取该文件中的数据作为用例的测试数据。
首先将用户名和密码按行写入txt文件中,这里把用户名和密码用逗号“,”隔开。
user_file = open('username_login.txt','r') lines = user_file.readlines() user_file.close() for line in lines: username = line.split(',')[0] password = line.split(',')[1] print(username,password)
运行结果:
首先通过open()方法以读“r”的形式打开username_login.txt文件,使用readlines()方法按行读取txt文件,将获取到的每一行数据通过split()方法拆分出用户名和密码。Split()可以将一个字符串通过某一个字符为分割点拆分成左右两部分,这个以逗号(,)为分割点。Split()拆分出来的左右两部以数组的形式存放,所以[0]可以取到左半部分的字符串,[1]可以取到右半部分的字符串。
在上面的例子中循环便利出每一行数据的用户名和密码,得到想要的数据后就可以将其用于自动化测试脚本了。
读取CSV文件
那么新的问题来了,假设现在每次要读取的是一组用户数据,这一组数据包括用户名、邮箱、年龄、性别等信息,这时在使用txt文件来存放这些数据,读取起来就没那么方便了。对于这类型的数据可以通过CSV文件来存放。
创建info.csv文件,首先通过WPS表格或Excel创建表格,文件另存为CSV格式进行保存。注意不要通过直接修改文件的后缀名来创建CSV文件,这样创建的并非真正的CSV类型文件。
下面编写csv_read.py文件进行循环读取
import csv #导入csv包 #读取本地CSV文件 date = csv.reader(open('info.csv','r')) #循环输出每一行信息 for user in date: print(user)
运行结果:
首先导入cvs模块,通过reader()方法读取CSV文件;然后通过for循环便利文件中的每一行数据。
从打印结果可以看出,读取的每一行数据均是以数组的形式存储的。如果向取用户的某一列数据,只需要指定数组下标即可。
import csv #导入csv包 #读取本地CSV文件 date = csv.reader(open('info.csv','r')) #获取用户的邮箱地址 for user in date: print(user[1])
运行结果:
假如现在需要所有用户的邮箱地址,那么只需要指定邮箱地址所在列的下标即可。数据的下标是以0开始的,邮箱位于数组的第二列,所以指用户邮箱的下标为[1]。
通过这种CVS文件来存放数据可以方便地解决读取多列数据的问题。当然,用Excel文件来存放这些数据也是一个不存的选择,只是所调用的模块就需要从csv切换为xlrd,针对Excel文件操作的方法也会有所不同。
读取xml文件
有时候我们需要读取的数据不是规则的。例如,我们需要一个配置文件来配置当前自动化测试脚本的URL、浏览器、登录的用户名和密码等,这时候就可以考虑选择使用XML文件来存放这些信息。新建info.xml文件
<?xml version='1.0' encoding='utf-8'?> <info> <base> <platform>Windows</platform> <browser>Firefox</browser> <url>http://www.baidu.com</url> <login username="admin" password="123456" /> <login username="guest" password="654321" /> </base> <test> <province>北京</province> <province>广东</province> <city>深圳</city> <city>珠海</city> <province>浙江</province> <city>杭州</city> </test> </info>
下面以info.xml文件为例介绍读取XML文件的方法。
1.获得标签信息
from xml.dom import minidom #打开xml文档 dom = minidom.parse('info.xml') #得到文档元素对象 root = dom.documentElement print(root.nodeName) print(root.nodeValue) print(root.nodeType) print(root.ELEMENT_NODE)
运行结果:
首先导入xml的minidom模块,用来处理XML文件,parse()用于打开一个XML文件,documentElement用于得到XML文件的唯一根元素。
每一个节点都有它的nodeName、nodeValue、nodeType等属性。nodeName为节点名称;nodeValue为节点的值,支队文本节点有效;nodeType为节点的类型。
2.获得任意标签名
from xml.dom import minidom #打开xml文档 dom = minidom.parse('info.xml') #得到文档元素对象 root = dom.documentElement tagname = root.getElementsByTagName('browser') print(tagname[0].tagName) tagname = root.getElementsByTagName('login') print(tagname[1].tagName) tagname = root.getElementsByTagName('province') print(tagname[2].tagName)
运行结果:
getElementsByTagName()可以通过标签名获取标签,它所获取的对象是以数组形式存放。假如“login”和“province”标签在info.xml文件中有多个,则可以通过指定数组的下标方式获取某个具体标签。
getElementsByTagName(“province”)获得的是标签名为“province”的一组标签;
getElementsByTagName(“province”).tagname[0]表示一组标签的第一个;
getElementsByTagName(“province”).tagname[1]表示一组标签的第而个。
3.获得标签的属性值
__author__ = 'Mr.Li' from xml.dom import minidom #打开xml文档 dom = minidom.parse('info.xml') #得到文档元素对象 root = dom.documentElement logins = root.getElementsByTagName('login') #获得login标签的username属性值 username = logins[0].getAttribute("username") print(username) #获得login标签的password属性值 password = logins[0].getAttribute("password") print(password) #获得第二个login标签的username属性值 username = logins[1].getAttribute("username") print(username) #获得第二个login标签的password属性值 password = logins[1].getAttribute("password") print(password)
运行结果:
getAttribute()方法用于获取元素的属性值。它和WebDriver中提供的get_attribute()方法相似。
4.获得标签对之间的数据
__author__ = 'Mr.Li' from xml.dom import minidom #打开xml文档 dom = minidom.parse('info.xml') #得到文档元素对象 root = dom.documentElement provinces = dom.getElementsByTagName('province') citys = dom.getElementsByTagName('city') #获得第二个province标签对的值 p2 = provinces[1].firstChild.data print(p2) #获得第一个city标签对的值 c1 = citys[0].firstChild.data print(c1) #获得第二个city标签对的值 c2 = citys[1].firstChild.data print(c2)
运行结果
firstChild属性返回被选节点的第一个子节点。data表示获取该节点的数据,它和WebDriver中提供的text方法类似。