测试学习记录,仅供参考!
数据驱动
结合 pytest 框架参数化处理对测试用例做参数化;介绍 Json 格式文件、yaml 格式文件、Excel 格式文件 三种文件方式去做测试用例参数化;
三、使用Excel文件对测试用例做参数化
简介
在日常工作中,经常需要处理Excel 数据,例如读取、写入、修改、分析等等。
使用Excel文件存放测试用例,可以使得测试数据更加直观和易于管理。
Python 是一种强大的编程语言,可以通过其丰富的第三方库来操作 Excel。但是,直接使用原生库进行操作可能会比较繁琐,不够简洁高效。因此,可以封装一个工具类,来简化Excel的操作过程,提高开发、测试效率。
安装
使用 openpyxl 模块处理 Excel 数据(若选择其他第三方库,其他模块自行学习了解);
安装第三方库 openpyxl 模块;
pip install openpyxl


示例:封装读取 Excel 文件方法
1、在项目根目录 data 目录文件下新建一个名称为 login_test.xlsx 的 Excel 文件;
注意:若使用 openpyxl 模块,读取的 Excel 文件的后缀扩展名务必是 XX.xlsx ".xlsx"格式;
因为这是新版 Windows 系统创建 Excel 文件的格式,以前旧版本(2023 版) xls (xlrd 库)格式可能不支持;
如若有安装其他软件工具文件格式,自行选择对应的第三方库版本;

2、可以再新建一个名称为 login_testdata.xls 的文件比较;
openpyxl.utils.exceptions.InvalidFileException: openpyxl does not support the old .xls file format, please use xlrd to read this file, or convert it to the more recent .xlsx file format.

openpyxl.utils异常。InvalidFileException:openpyxl不支持旧的.xls文件格式,请使用xlrd读取此文件,或将其转换为较新的.xlsx文件格式。

3、在文件中填写相同的内容后保存;


4、 重新新建一个正常的xlsx文件,覆盖异常文件;
5、 可以在桌面新建一个 Excel 文件,复制到项目 data 目录下;或直接在 data 目录下右键菜单新建一个.xlsx 文件;

处理行数据
6、创建一个文件去读取 Excel 文件的数据内容;
7、在 handle_data 软件包下新建名称为 operateExcel.py(专门处理 Excel 相关文件) 的 Python 文件;
1)、 首先,引进 openpyxl 模块 load_workbook 方法;
2)、 再引入 openpyxl 的一个异常处理,需要用到;
3)、 引进日志,因为需要打印日志;
4)、 创建一个类 class ExcelDataReader:
(因为读取 Excel 文件稍微比较复杂,不像是 Json、yaml 写一个函数就行,所以封装成类的方式)
5)、 写一个初始化构造方法,里面带一个(文件路径 file_path)参数 def init(self, file_path):
6)、 定义一个实例属性 self.file_path = file_path 当实例化 ExcelDataReader 时,需要传一个路径给它;
7)、 引入 os 模块,写一下相对路径 abspath = os.path.abspath(self.file_path) 给返回出去;
8)、 判断'当传进来的这个路径'不存在的情况下,抛出一个异常提示;
9)、 调用 openpyxl 库中的 load_workbook() 方法,里面第一个参数传一个文件,只读模式默认 False;

10)、最后把这个对象给返回出去,后续会使用到;到这一步初始化构造函数已经写完了;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
11)、初始化构造函数完成之后,开始写操作 Excel 文件里面的数据,例如:获取文件里面一整行的数据;
12)、获取某一行的数据信息,自定义一个 def read_entire_row(): 方法 ;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 打印查看是什么数据
print(sheet)
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件的相对路径
exl = ExcelDataReader('../../data/login_test.xlsx')
# 通过实例化类对象去调用 read_entire_row() 方法
exl.read_entire_row()
13)、运行查看结果,因为这两个 sheet_name='Sheet1', row_index=1 参数有默认值,所以可以不填;
拿到的是第一个 Sheet 的对象
<Worksheet "Sheet1">
进程已结束,退出代码为 0
14)、这个 Sheet 对象肯定不是需要的一个结果,所以继续优化,增加列表推导式;
(1)[for cell in sheet] 在 sheet 中去循环 cell 它;
(2)[for cell in sheet[row_index]] 要获取哪一行的数据;
(3)[cell.value for cell in sheet[row_index]] 通过循环这个生成器对象,通过这个对象获取它的值;
(4)rows_data = [cell.value for cell in sheet[row_index]] 把结果返回出去;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 列表推导式
rows_data = [cell.value for cell in sheet[row_index]]
print(rows_data)
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件路径
exl = ExcelDataReader('../../data/login_test.xlsx')
# 通过实例化类对象去调用 read_entire_row() 方法
exl.read_entire_row()
15)、能够获取到第一行的数据信息;
['username', 'password']
进程已结束,退出代码为 0
16)、获取指定行的数据;
if __name__ == '__main__':
exl = ExcelDataReader('../../data/login_test.xlsx')
# 获取第二行的数据
exl.read_entire_row(row_index=2)
结果:
['admin123', 123456]
进程已结束,退出代码为 0
17)、拿到全部行的数据(每一行每一条数据),定义一个 def read_multiple_rows(): 方法 ;与使用 Json、yaml文件相似,返回的是全部数据,一个列表里面跟上一个元组(一组数据是一个元组) ;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 列表推导式
rows_data = [cell.value for cell in sheet[row_index]]
return rows_data
def read_multiple_rows(self, sheet_name='Sheet1'):
"""
读取Excel多行的数据,每一行数据组成一个列表
:param sheet_name: sheet页名称
:return: 返回list,例如:[['admin123','123456'],[],[],...]
"""
# 第一步跟上面一样,先拿到sheet这个对象
sheet = self.workbook[sheet_name]
# 调用 max_column 方法获取到最大的列数(行数 .max_row)
max_col = sheet.max_column
print(max_col)
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件路径
exl = ExcelDataReader('../../data/login_test.xlsx')
# 通过实例化类对象去调用对应的方法
exl.read_multiple_rows()
18)、运行查看 Excel 文件中有多少列数;
2
进程已结束,退出代码为 0
19)、拿到了列数之后,需要去循环它;
(1)、for row in sheet.iter_rows(): sheet.iter_rows() 是循环'行'的生成器;
(2)、min_row=1, max_row=sheet.max_row, min_col=1, max_col=max_col
min_row :获取起始行,从第几行开始去读取数据
max_row :获取当前工作簿最大的行数(根据单元格有木有数据)
min_col :获取起始列,从第几列开始去读取数据
max_col :获取最大列数
(3)、都拿到这些(行数、列数)数据之后才会去循环读取 Excel 文件当前工作簿里面的数据;
(4)、写一个列表推导式去循环这个对象;循环每一个的对象,通过循环生成器对象获取每个单元格的值,最后给返回出去;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 列表推导式
rows_data = [cell.value for cell in sheet[row_index]]
return rows_data
def read_multiple_rows(self, sheet_name='Sheet1'):
"""
读取Excel多行的数据,每一行数据组成一个列表
:param sheet_name: sheet页名称
:return: 返回list,例如:[['admin123','123456'],[],[],...]
"""
# 第一步跟上面一样,先拿到sheet这个对象
sheet = self.workbook[sheet_name]
# 调用 max_column 方法获取到最大的列数(行数 .max_row)
max_col = sheet.max_column
# 1
for row in sheet.iter_rows(min_row=1, max_row=sheet.max_row, min_col=1, max_col=max_col):
# row 是一个迭代器对象--但是不是需要获取的结果(单元格名称,例如:A1、B1、A2...)
# print(row)
# 列表推导式
row_data = [cell.value for cell in row]
print(row_data)
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件路径
exl = ExcelDataReader('../../data/login_test.xlsx')
# 通过实例化类对象去调用对应的方法
exl.read_multiple_rows()
20)、打印查看结果(已成功拿到每一行的数据了)
['username', 'password']
['admin123', 123456]
['admin111', 123456]
['admin123', 111111]
['admin', None]
进程已结束,退出代码为 0
21)、把获取到的每一行数据汇合到一个总的列表中存储起来;
在最外层定义一个空列表;把每一行的数据都追加到这个列表中;然后把结果返回出去就行了;
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 列表推导式
rows_data = [cell.value for cell in sheet[row_index]]
return rows_data
def read_multiple_rows(self, sheet_name='Sheet1'):
"""
读取Excel多行的数据,每一行数据组成一个列表
:param sheet_name: sheet页名称
:return: 返回list,例如:[['admin123','123456'],[],[],...]
"""
# 在最外层定义一个空列表
all_rows_data = []
# 第一步跟上面一样,先拿到sheet这个对象
sheet = self.workbook[sheet_name]
# 调用 max_column 方法获取到最大的列数(行数 .max_row)
max_col = sheet.max_column
for row in sheet.iter_rows(min_row=1, max_row=sheet.max_row, min_col=1, max_col=max_col):
# row 是一个迭代器对象
# print(row)
# 列表推导式
row_data = [cell.value for cell in row]
# 调用append方法追加每一行的数据
all_rows_data.append(row_data)
return all_rows_data
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件路径
exl = ExcelDataReader('../../data/login_test.xlsx')
# 直接打印
print(exl.read_multiple_rows())
22)、打印查看结果(这才能需要返回的数据结果)
[['username', 'password'], ['admin123', 123456], ['admin111', 123456], ['admin123', 111111], ['admin', None]]
进程已结束,退出代码为 0
增加日志和异常处理方式
8、添加'异常处理'和'日志',增加"关闭"(关闭文件,释放资源)的一个操作;
因为文件操作最好是写一个关闭文件方法,释放内存空间;
finally 语句块用于包裹必须无论异常是否发生都要执行的代码。通常,它用于执行资源清理、文件关闭或其他类似操作。无论 try 块中的代码是否引发异常,finally 块中的代码都会执行。
# 引进 openpyxl 模块 load_workbook 方法
from openpyxl import load_workbook
# 引入 openpyxl 的一个异常处理
from openpyxl.utils.exceptions import InvalidFileException
# 引入日志
from util_tools.logs_util.recordlog import logs
# 引入os模块
import os
# 创建一个类
class ExcelDataReader:
"""
读取Excel文件数据
"""
# 写一个初始化构造方法
def __init__(self, file_path):
# 定义实例属性
self.file_path = file_path
# 写一下相对路径并返回出去
abspath = os.path.abspath(self.file_path)
# if判断 传进来的文件路径不存在(没有找到)时
if not os.path.isfile(abspath):
# 抛出异常提示
raise FileNotFoundError(f'文件路径不存在:{abspath}')
# read_only:控制工作簿是否以只读模式打开,若为True,工作簿以只读模式打开,不允许对工作簿进行修改
self.workbook = load_workbook(self.file_path, read_only=False)
def read_entire_row(self, sheet_name='Sheet1', row_index=1):
"""
获取Excel文件一整行的数据
:param sheet_name: sheet页名称
:param row_index: 要返回哪一行的数据,索引从1开始
:return:
"""
# 调用上面初始化的打开这个文件的对象 self.workbook 列表里面是获取哪一行它的名称
sheet = self.workbook[sheet_name]
# 列表推导式
rows_data = [cell.value for cell in sheet[row_index]]
return rows_data
def read_multiple_rows(self, sheet_name='Sheet1'):
"""
读取Excel多行的数据,每一行数据组成一个列表
:param sheet_name: sheet页名称
:return: 返回list,例如:[['admin123','123456'],[],[],...]
"""
try:
# 在最外层定义一个空列表
all_rows_data = []
# 第一步跟上面一样,先拿到sheet这个对象
sheet = self.workbook[sheet_name]
# 调用 max_column 方法获取到最大的列数(行数 .max_row)
max_col = sheet.max_column
for row in sheet.iter_rows(min_row=1, max_row=sheet.max_row, min_col=1, max_col=max_col):
# row 是一个迭代器对象
# print(row)
# 列表推导式
row_data = [cell.value for cell in row]
# 调用append方法追加每一行的数据
all_rows_data.append(row_data)
return all_rows_data
except Exception as e:
logs.error(f'读取所有行数据异常,原因为:{e}')
finally:
self.close()
def close(self):
self.workbook.close()
# 调试查看
if __name__ == '__main__':
# 实例化类--里面是文件路径
exl = ExcelDataReader('../../data/login_test.xlsx')
print(exl.read_multiple_rows())
未完待续。。。