使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 24--数据驱动--参数化处理 Excel 文件 1

测试学习记录,仅供参考!

数据驱动

结合 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())

未完待续。。。

相关推荐
Nebula_g1 小时前
C语言应用实例:学生管理系统1(指针、结构体综合应用,动态内存分配)
c语言·开发语言·学习·算法·基础
小叮当⇔1 小时前
“征服式学习”提示词工具箱
学习·算法
安冬的码畜日常2 小时前
【JUnit实战3_29】第十八章:REST API 接口测试(上)——RESTful 风格的后端 API 的搭建
测试工具·单元测试·restful·rest api·junit 5
开心-开心急了2 小时前
关于Flutter与Qt for python 的一些技术、开源、商用等问题
开发语言·python·qt·flutter
Mark_Hide2 小时前
学习笔记7
笔记·学习
@小码农2 小时前
2025年北京海淀区中小学生信息学竞赛第一赛段试题(附答案)
人工智能·python·算法·蓝桥杯
d111111111d2 小时前
STM32外设学习--TIM定时器--编码器接口(程序)
笔记·stm32·嵌入式硬件·学习
Anesthesia丶2 小时前
UV工具学习笔记
笔记·学习·uv
我的golang之路果然有问题2 小时前
mac M系列芯片 unity 安装会遇到的错误以及解决
经验分享·学习·macos·unity·游戏引擎