二、数据驱动测试(ddt)
1.应用场景:使用多组测试数据来测试同一个业务流程的功能。
2.ddt:data-driven test,数据驱动测试,是指测试数据的改变驱动测试结果的改变,通俗的来说,就是想要使用多组测试数据来测试同一个业务流程时,把测试数据从测试脚本
中提取出来,可以存储在一个元组、列表、字典类型的变量里,或也可以提取到json、yaml、csv、excel等格式的数据文件里来存储,只写一次测试脚本,描述测试的业务流程,
使用这些数据来自动反复执行测试脚本。
3.ddt优势:数据和脚本都更方便进行维护管理。在测试工作中,ddt是建议使用的测试代码设计模式。
4.python语言版本的selenium webdriver里要想使用ddt模式,必须安装一个Python语言的第三方模块,名称是ddt
(1)在线安装:管理员身份运行起来的cmd里多次输入
pip install ddt -i https://pypi.douban.com/simple,回车,直到最后提示Requirement already satisfied: ddt……代表已经安装过了。
(2)离线安装:百度网盘Selenium资料ddt-1.2.1.tar.gz,复制到D盘根目录,解压缩到当前文件夹,查看出现D:ddt-1.2.1setup.py,cmd里输入D:切换到D盘,
cd ddt-1.2.1切换进入文件夹里,输入python setup.py install
示例:
C:Windowssystem32>D:
D:>cd ddt-1.2.1
D:ddt-1.2.1>python setup.py install
……
(3)安装方式三:Pycharm里菜单File---Settings---Project---Project Interpreter---查看列表里是否有ddt模块,没有的话,点击右侧+按钮,搜索ddt,
点击下方Install Package按钮来在线安装。
(4)检查ddt是否安装好:pycharm里某个python文件里输入from ddt import ddt,如果没有报错,就代表安装好了。
(5)如果无法使用ddt,重启Pycharm再次尝试。
5.ddt使用步骤:
(1)新建python unit test文件,实现用第一组数据来测试的整个业务代码。
(2)从ddt模块导入ddt和data两个python装饰器。
from ddt import ddt,data
(3)使用@ddt写在class定义语句的前一行,表示该类要用ddt模式运行(也就是指本类里的测试函数要反复执行)。
@ddt
class XXX
(4)使用@data(数据1,数据2……)写在测试函数定义语句的前一行
语法:
@data(数据1,数据2……)
def test_xxx
(5)在使用@data修饰后的测试函数名称后小括号里增加一个形参变量,代表传入进来的数据
示例:
@data("a","b","c")
def test_something(self,k):
(6)在测试函数函数体里使用这个形参变量来代表传入进来的数据。
示例:guan.send_keys(k)
(7)注意:运行之前,必须要把光标放在代码末尾来运行,不要把光标放在测试函数函数体里。
案例:使用不同的搜索关键字来做ecshop前台搜索功能的测试
关键字
a
b
c
一、数据驱动测试(ddt)
6.ddt的unpack装饰器的用法:
(1)应用场景:unpack装饰器用于每一组测试数据由多个值的组成的情况。
(2)unpack装饰器可以元组、列表、字典类型数据的解包(拆包)操作,负责把集合拆开,把其中的多个值提取出来给测试函数来使用。
(3)具体使用步骤:
a.从ddt模块导入ddt、data、unpack三个装饰器
from ddt import ddt,data,unpack
b.在测试函数前@data([值1,值2,值3……],[值1,值2,值3……],……)用元组、列表或字典来准备测试数据,每组值写在一个集合里,各个数据集之间使用逗号分隔开。
注意:每组值的个数必须一致。
示例:
@data(["a", "4"], ["b", "1"], ["c", "24"])
c.在测试函数前再增加一个@unpack
d.在测试函数名称后小括号里准备与每组值的数据个数一致个数的形参变量。
示例:因为每组里有两个值,所以就需要准备两个形参变量,变量和值有按顺序的一一对应关系。
@data(["a", "4"], ["b", "1"], ["c", "24"])
@unpack
def test_something(self,k,e):
e.在测试函数的函数体里使用这些形参变量代表测试数据。
案例:使用不同的搜索关键字来做ecshop前台搜索功能的测试,搜索后检查总计的结果数是否等于预期值。
关键字 预期值
a 4
b 1
c 24
@data("a","4","b","1","c","24")
元组 ("a","4") ("b","1") ("c","24")
列表 ["a","4"] ["b","1"] ["c","24"]
字典 {"kw":"a","expected":"4"} {"kw":"b","expected":"1"}
{"kw":"c","expected":"24"}
from ddt import ddt,data,unpack
@data(["a", "4"], ["b", "1"], ["c", "24"])
@unpack
def test_something(self,k,e):
self.driver.get("http://localhost/upload/index.php")
guan=self.driver.find_element(By.ID,"keyword")
guan.send_keys(k)
sou=self.driver.find_element(By.CLASS_NAME,"go")
sou.click()
sleep(1)
jieguoshu=self.driver.find_element(By.XPATH,".//*[@id='pager']/span[1]/b")
self.assertEqual(e,jieguoshu.text)
练习:case9001.py,使用ddt技术来测试打开ECSHop前台留言板页,输入不同的电子邮件地址、主题、留言内容的步骤。
电子邮件地址 主题 留言内容
lisi@163.com 关于手机电池问题 手机电池故障
zhangsan@126.com 求购手机 新款手机是否有货
7.问题:单选按钮这样的测试数据该如何准备?
解决方案一:在@data后的数据里写单选按钮的索引号(从0开始编号的整数),在测试函数中使用find_elements获得所有单选按钮,再对它返回来的list使用数据里准备的索引号
来获得指定的一个单选按钮,最后点击它。
示例:
@data(["lisi@163.com",3,"关于手机电池问题","手机电池故障"],["zhangsan@126.com",4,"求购手机","新款手机是否有货"])
@unpack
def test_something(self,e,d,t,c):
……
lei=self.driver.find_elements(By.NAME,"msg_type")[d]
lei.click()
解决方案二:数据里准备一些汉字描述是哪个单选按钮,在测试函数体里根据汉字内容不同,来选择不同单选按钮,可以使用分支结构语句(if……elif……elif……)实现,或者也可以
用循环结构来循环判断(for …… if……)。
示例:
@data(["lisi@163.com","售后","关于手机电池问题","手机电池故障"],["zhangsan@126.com","求购","求购手机","新款手机是否有货"])
@unpack
def test_something(self,e,d,t,c):
……
a1=["留言","投诉","询问","售后","求购"]
for i in range(len(a1)):
print(i)
if a1[i]==d:
lei = self.driver.find_elements(By.NAME, "msg_type")[i]
lei.click()
break
练习:case9001.py,使用ddt技术来测试打开ECSHop前台留言板页,输入不同的电子邮件地址、主题、留言内容的步骤。
电子邮件地址 留言类型 主题 留言内容
lisi@163.com 售后 关于手机电池问题 手机电池故障
zhangsan@126.com 求购 求购手机 新款手机是否有货
二、从外部文件读取测试数据
1.支持外部文件:json、yaml、csv、excel等。课程里主要讲解csv格式文件读取。
2.逗号分隔值(Comma-Separated Values,CSV)其文件以纯文本形式存储表格数据(数字和文本),文件后缀是.csv,可以使用记事本这样的文本编辑器来生成csv文件,也可以
使用excel这样的表格编辑器来生成csv文件。
3.创建csv文件:新建文本文档,用记事本打开它,输入用逗号分隔开的数据值,每组值写在一行,最后用记事本菜单里的文件---另存为---保存类型:所有文件(*.*)---输入文件名
称:xxx.csv---如果有中文内容,选字符集编码格式:utf-8,否则用默认的ANSI即可---保存。
4.读取csv工具类文件:百度网盘Selenium资料
ead_csv.py,复制到某个包里。
5.新建Python unit test的python文件里,导入read_csv模块里的CSVUtil类,在unit test测试类之前先书写一段代码来读取外部文件里的数据,存储到一个变量里,
在@data后小括号里使用这些数据:
(1)导入CSVUtil
from day09.read_csv import CSVUtil
(2)实例化CSVUtil对象,构造函数需要传入csv文件路径,可以是绝对路径(从盘符开始写的文件路径),也可以是相对路径(.代表当前文件所在包的文件夹,..当前文件所在包
的文件夹的上一级文件夹)。
示例:
filePath = "./td.csv"#"E:/Selenium/td.csv"
u = CSVUtil(filePath)
(3)调用该CSVUtil类的无参的list_data函数,接收返回来的数据,存储在变量里,该数据的类型是大列表里嵌套多个小列表([[x,x,x,x],[x,x,x,x]])。
示例:
d=u.list_data()
(4)在@data后小括号里使用这些数据时,需要使用*变量名称的形式,其中*负责对大列表做解包操作,@unpack负责对小列表解包。
注意:测试函数的形参变量个数应该与csv里每行数据值的个数一致。
示例:
@data(*d)
@unpack
def test_xxx(self,x,y,z)
练习:把case9002.py复制,粘贴day09包,修改文件名称为case9004.py,制作新的csv文件(名称是td2.csv)用来记录9004里那些测试数据,最后修改9004的代码,让它来
使用csv文件里的数据做测试。
6.常见问题:如果保存csv文件时,不修改字符集编码格式,不用修改read_csv.py,如果保存csv文件时,选择字符集编码是utf-8,那么使用百度网盘里的read_csv.py来读取
数据,就会报错UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 56: illegal multibyte sequence
解决方案:如果保存csv文件时,选择字符集编码是utf-8,那么需要打开read_csv.py,修改第10行代码
with open(self.filePath, "r") as f:
===》增加open函数的encoding参数设置为utf-8的值。
with open(self.filePath, "r",encoding="utf-8") as f:
案例:使用不同的搜索关键字来做ecshop前台搜索功能的测试,搜索后检查总计的结果数是否等于预期值。
关键字 预期值
a 4
b 1
c 24