1. 用例分离
-- 一组测试数据-->一个用例-->测试类下的一个方法
-- 先用手工测试的用例:excel,xmind,tapd,testrail
测试数据的运转:手工写到excel中-->python读取excel数据-->自动化测试方法/函数
2. openpyxl
在我们读取excel前,需要安装一个第三方库,专门操作excel。
如:openpyxl(比较主流),xlrd(适合老版本,只能读取数据,不能写入等),pandas(比较重量级,安装的东西比较多,而且容易出错)
先来了解execl表格:
工作簿(workbook):指的就是整个excel文件
表格(sheet):一个工作簿中可以包括多个表格,也就是sheet1,sheet2....
行(row):就是sheet表格中的一行
列(column):就是sheet表格中的一列
单元格(cell):就是sheet表格中的一个格子
python读取excel操作步骤:
第一步:在桌面上新建了一个cases.xlsx表格,增加了两条数据,如下
第二步:安装openpyxl,读取excel表格数据。如下
安装完成后,开始读取数据
# 导入load_workbook:作用是加载工作簿
from openpyxl import load_workbook
# 通过文件得到一个工作簿,参数是文件名,如果有路径,要写绝对路径
wb = load_workbook('cases.xlsx')
print(wb)
# 获取 sheet 表格
sheet = wb['Sheet1'] # 注意S是大写的
print(sheet)
# 获取一个单元格
cell = sheet.cell(row=2,column=1)
print(cell)
# 获取单元格的值/内容
print(cell.value)
运行结果:
<openpyxl.workbook.workbook.Workbook object at 0x00000226B9510220>
<Worksheet "Sheet1">
<Cell 'Sheet1'.A2>
1
踩坑点:
获取sheet中所有的数据:
# 导入load_workbook:作用是加载工作簿
from openpyxl import load_workbook
wb = load_workbook('cases.xlsx')
sheet = wb['Sheet1']
# 获取sheet中所有的数据
data = sheet.values
print(data) # 得到的一个结果generator的对象,这个是可以转换成列表格式
print(list(data))
运行结果:
<generator object Worksheet.values at 0x000001649E85F2E0>
[('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]
自动化测试过程不会每次都这样一行一行的写,我们会封装成一个函数,当使用的时候直接来调用函数
from openpyxl import load_workbook
# 封装读取excel的函数
def read_excel(file_name, sheet_name):
# 获取工作簿
wb = load_workbook(file_name)
# 获取表格
sheet = wb[sheet_name]
# 获取表格中的数据
data = list(sheet.values)
return data
result = read_excel('cases.xlsx', 'Sheet1')
print(result)
运行结果:
[('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]
如果只想获取测试内容,不想要第一行内容,那么return的内容可以改成return data[1:],其他内容不用修改
from openpyxl import load_workbook
# 封装读取excel的函数
def read_excel(file_name, sheet_name):
# 获取工作簿
wb = load_workbook(file_name)
# 获取表格
sheet = wb[sheet_name]
# 获取表格中的数据
data = list(sheet.values)
return data[1:]
result = read_excel('cases.xlsx', 'Sheet1')
print(result)
运行结果:
[(1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]
如果不要第一行内容,时间长了,会不记得每个数据代表的是什么,所以我们要把[[ ],[ ],[ ]]/[( ),( ),( )]格式转换成[{ },{ },{ }],如何转换如下
from openpyxl import load_workbook
from pprint import pprint
# 封装读取excel的函数
def read_excel(file_name, sheet_name):
# 获取工作簿
wb = load_workbook(file_name)
# 获取表格
sheet = wb[sheet_name]
# 获取表格中的数据
data = list(sheet.values)
return data
result = read_excel('cases.xlsx', 'Sheet1')
# [[ ],[ ],[ ]]/[( ),( ),( )]格式转换成[{ },{ },{ }]
new_list = []
for value in result[1:]:
new_list.append(dict(zip(result[0],value)))
pprint(new_list)
运行结果:
[{'case_id': 1, 'data': '数据1', 'expected': '成功', 'title': '测试用例1'},
{'case_id': 2, 'data': '数据1', 'expected': '失败', 'title': '测试用例2'}]
3.excel结合测试用例使用
unittest 是测试函数或类下面的方法是否可以正常使用,当测试人员自己写了个函数时,也是可以用unittest来进行测试是否可以正常使用的
第一步:准备测试数据,函数实际参数,放到了模块test_excel.py下
第二步:准备预期结果,放到了模块run_test_excel.py下
第三步:测试,调用read_excel函数,得到实际结果
test_excel.py模块具体代码如下:
from openpyxl import load_workbook
def read_excel(file_name, sheet_name):
wb = load_workbook(file_name)
sheet = wb[sheet_name]
data = list(sheet.values)
return data
run_test_excel.py模块具体代码如下:
import unittest
from test_excel import read_excel
class TestExcel(unittest.TestCase):
def test_excel(self):
file = 'cases.xlsx'
sheet_name = 'Sheet1'
expected = [('case_id', 'title', 'data', 'expected'),
(1, '测试用例1', '数据1', '成功'),
(2, '测试用例2', '数据1', '失败')]
actual = read_excel(file, sheet_name)
self.assertEqual(expected, actual)
运行结果:
但在实际工作中,不会这样去写一个类去测试自己写的测试用例,会使用下面的方法去测试
from openpyxl import load_workbook
def read_excel(file_name, sheet_name):
wb = load_workbook(file_name)
sheet = wb[sheet_name]
data = list(sheet.values)
return data
# 输入main会自动写全if __name__ == '__main__':
if __name__ == '__main__':
data = read_excel('cases.xlsx', 'Sheet1')
print(data)
按左边的播放键即可,但通过其他模块去调用此模块,不会运行main下的内容
运行结果:
[('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]
举个栗子:
login.py模块具体代码如下:
def login(username=None, password=None):
if username is None or password is None:
return {"code": "400", "msg": "用户名或密码为空"}
if username == 'yuz' and password == '123':
return {"code": "200", "msg": "登录成功"}
return {"code": "300", "msg": "用户名或密码错误"}
test_login.py模块具体代码如下:
from login import login
import unittest
class TestLogin(unittest.TestCase):
def test_login_01(self):
username = ''
password = ''
expected = {"code": "400", "msg": "用户名或密码为空"}
actual = login(username, password)
self.assertEqual(expected, actual)
def test_login_02(self):
username = 'li'
password = '123'
expected = {"code": "300", "msg": "用户名或密码错误"}
actual = login(username, password)
self.assertEqual(expected, actual)
def test_login_03(self):
username = 'yuz'
password = '123'
expected = {"code": "200", "msg": "登录成功"}
actual = login(username, password)
self.assertEqual(expected, actual)
运行结果:
这样去做自动化测试的缺点:
1. 一个用例要单独编写一个函数,存在重复性代码(可以通过数据驱动ddt解决)
2. 测试数据维护不方便,增加,修改,需要查找很多代码,一一修改(可以通过测试数据单独管理,如放到excel、yaml中)
因此,我们改进放到一个自动化测试方法来完成所有测试用例,此时就需要用for循环
具体步骤如下:
第一步:新建一个login.xlsx表格来存放所有用例
第二步:修改之前的test_excel.py,代码如下:
from openpyxl import load_workbook
def read_excel(file_name, sheet_name):
wb = load_workbook(file_name)
sheet = wb[sheet_name]
data = list(sheet.values)
# 取出表格中的第一行内容
titles = data[0]
# 用列表推导式转换成列表嵌套字典
rows = [dict(zip(titles,row)) for row in data[1:]]
return rows
第三步:修改之前的test_login.py模块,代码如下:
import unittest
from login import login
from test_excel import read_excel
# 调用test_excel下的read_excel函数
data = read_excel('login.xlsx', 'Sheet1')
class TestLogin(unittest.TestCase):
def test_login(self):
# 循环列表嵌套字典的数据
for row in data:
# 循环取出每行数据,并转换成字典类型,因为取出的是str类型
params = eval(row['data'])
# 取出用户名与密码
username = params['username']
password = params['password']
# 取出预期结果
expected = row['expected']
actual = login(username, password)
self.assertEqual(expected, actual)
注意:
1.excel当中读取的data单元格数据是字符串,不是字典。需要用evel()方法处理
2.使用for循环操作时,unittest把所有测试用例当成一个测试用例去执行,实际上有3个测试用例
4.数据驱动
为了优化for循环带来的问题,因此需要数据驱动来做参数化
参数化:对于一个统一的逻辑(测试函数),使用不同的参数(数据)去执行
使用第三方库来实现:ddt,unittestreport,使用前请先安装,切换到terminal,输入命令点击回车即可完成安装:pip install ddt;pip install unittestreport,已安装过忽略
4.1 unittestreport中ddt
import unittest
from login import login
from test_excel import read_excel
from unittestreport import ddt, list_data
# 调用test_excel下的read_excel函数
data = read_excel('login.xlsx', 'Sheet1')
@ddt
class TestLogin(unittest.TestCase):
@list_data(data)
def test_login(self,row):
# row表示每次从data这个列表中取出一个数据,{}
# row代表一组测试数据,相当于for row in data:
# 源码:会自动生成一个新的test_login_1函数
params = eval(row['data'])
username = params['username']
password = params['password']
expected = eval(row['expected'])
actual = login(username, password)
self.assertEqual(expected, actual)
运行结果:
从结果可以看到,ddt的高级之处就是遇到了失败用例后,还会继续执行后面的测试用例,之间不会相互影响
参数化的具体使用过程:
1.导入unittestreport模块下的ddt,list_data
2.在测试函数当中,加入参数row,row参数是可以自己定义的
4.2 ddt
import unittest
from login import login
from test_excel import read_excel
from ddt import ddt,data
# 调用test_excel下的read_excel函数
excel = read_excel('login.xlsx', 'Sheet1')
@ddt
class TestLogin(unittest.TestCase):
# 一定要注意*
@data(*excel)
def test_login(self,row):
# row表示每次从data这个列表中取出一个数据,{}
# row代表一组测试数据,相当于for row in data:
# 源码:会自动生成一个新的test_login_1函数
params = eval(row['data'])
username = params['username']
password = params['password']
expected = eval(row['expected'])
actual = login(username, password)
self.assertEqual(expected, actual)
运行结果:
excel结合测试用例的用法总结:
为什么要用excel单独管理用例:便于维护
具体用法:
1.read_excel读取excel当中的数据
2.通过参数化完成,数据到用例的结合
3.用例函数只需要写一个,数据可能有多个甚至上万个,节省了很多的测试用例函数
4.什么数据可以整合到一个用例函数?一定要是测试逻辑一致,只有数据不一致
注意事项:
1.excel当中不存在字典,如果单元格当中有文本,读出出来是字符串,字典是python当中的概念
2.参数化不要用for循环,因为for循环虽然一个函数可以执行多个数据,但是所有的数据被当成了一个测试用例,不会自动生成用例
参数化 vs 数据驱动
参数化:也就是函数参数,一个测试函数当中会参数,该参数往往就是测试数据
数据驱动(data driven testing,ddt):是一种思想,具体实现方式就是使用参数化