使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 23--数据驱动--参数化处理 Yaml 文件
测试学习记录,仅供参考!
数据驱动
结合 pytest 框架参数化处理对测试用例做参数化;介绍 Json 格式文件、yaml 格式文件、Excel 格式文件 三种文件方式去做测试用例参数化;
二、使用yaml文件对测试用例做参数化
Yaml是一种简洁的非标记语言,Yamll以数据为中心,使用空白、缩进、分行组织数据,从而使得表示更加简洁意读。由于实现简单,解析成本很低,Yaml特别适合在脚本语言中使用,Yaml是专门用来写配置文件的语言,非常简洁强大,远比JSON格式方便,一般使用 yaml 文件做数据配置比较多,但也有做参数化的,在接口自动化测试中,可用作配置文件,配置一些服务器域名、mysql配置、登录信息、toekn等数据信息,方便快速读取,像是接口的一些相关信息,都是用 yaml 文件去管理的;
Yaml 文件语法特点(规则):
1、大小写敏感,英文字母区分大小写;
2、使用缩进表示层级关系;
3、缩进时不允许使用Tab键,只允许使用空格;
4、缩进的空格数目不重要亦不固定,只需要相同层级的元素左侧对齐即可;
5、文件中的字符串不需要使用引号标注,但若字符串包含有特殊字符则需用引号标注;
6、key值前面带-表示这组数据是一个列表类型,两组数据的-属于同级关系的话,数据存在一个列表里面;
7、Yaml 文件中的注释标识符为 # 井号,在所在行最前面增加标识符 # 即为注释本行;
Yaml 文件数据结构
对象:键值对的集合(简称 "映射或字典"),包含key和 value;
键值对中间使用冒号 “:” 结构表示,冒号与值之间需用空格分隔;
key:描述对象属性的字符串;
value:可以是纯量、对象结合、数组;
数组:一组按序排列的值(简称 "序列或列表")
数组前加有 “-” 符号,以 - 开头的行表示构成一个数组,符号与值之间需用空格分隔;
纯量(scalars):单个的、不可再分的值(例如:字符串、bool值、整数、浮点数、时间、日期、Null等)
Yaml 安装
安装 yaml 库
pip install pyyaml
代码演示
1、在项目根目录 data 目录文件下新建名称为 login.yaml(login.yml 两种格式均行 ) 的 yaml 文件;
在 yaml 文件中列表以 “-”(一个横杠)展示,每一组数据以逗号分隔;
- admin123,123456
- admin123456,123456
- admin123,123456789
- admin123,yaml 文件亦是键值对的方式,但是需要注意冒号“:”后面要有一个空格,不然就会报错;且键值不能重复;

2、在 handle_data 软件包下新建名称为 readYaml.py(专门处理 yaml 文件) 的 Python 文件;
第一步,先导入 yaml 模块(如果导入不了 yaml 模块,需要先去安装 yaml 库)
直接写一个函数 def read_yaml(file_path): 里面传一个参数(读取哪个 yaml 文件的路径);
import yamldef read_yaml(file_path):"""读取yaml文件的数据:param file_path: yaml文件路径:return: 返回列表类型,列表里面是元组数组"""with open(file_path, 'r', encoding='utf-8') as file:# 添加这个 Loader=yaml.FullLoader 参数后不会在控制台输出警告信息data = yaml.load(file, Loader=yaml.FullLoader)return data# 调用函数调试--相对路径
res = read_yaml('../../data/login.yaml')
print(res)3、运行 readYaml.py 文件查看结果,最外层是一个列表,里面每一组是一个字符串;
['admin123,123456', 'admin123456,123456', 'admin123,123456789', 'admin123,']进程已结束,退出代码为 04、这种格式在 test_login.py 文件中做参数化时还需要处理才能拿到每一个数据,与其在 test_login.py 文件中做处理,还是直接在 readYaml.py 读取 yaml 文件中做处理更方便;
5、优化 readYaml.py 文件;
1)、 for data_str in data: 首先,循环一下列表中的每组数据,因为每组数据是字符串类型;
2)、if data_str is not None: 加一个判断,防止 yaml 文件中有空数据的场景;
3)、data_str.split(',') 调用指定的方法,通过 ,逗号 对每一组数据进行分割;
4)、tuple(data_str.split(',')) 分割之后转换成元组类型
5)、data_tuple = tuple(data_str.split(',')) 把结果返回出去;
此时,若 return data_tuple 调式查看结果是只返回了一组数据(最后一组);
6)、因为需要返回全部的数据信息,所以在最外层定义一个 data_list_tuple = [] 空的列表;
7)、data_list_tuple.append(data_tuple) 把所有数据追加到这个 data_list_tuple 空列表中;
8)、return data_list_tuple 这时候把最外层这个列表给返回出去即可;
import yaml
from nibabel.testing import data_pathdef read_yaml(file_path):"""读取yaml文件的数据:param file_path: yaml文件路径:return: 返回列表类型,列表里面是元组数据,如:[('admin123','123456'),(),(),()......]"""# 在最外层定义一个空列表data_list_tuple = []with open(file_path, 'r', encoding='utf-8') as file:# 添加这个 Loader=yaml.FullLoader 参数后不会在控制台输出警告信息data = yaml.load(file, Loader=yaml.FullLoader)for data_str in data:if data_str is not None:data_tuple = tuple(data_str.split(','))data_list_tuple.append(data_tuple)return data_list_tuple# 调用函数调试--相对路径
res = read_yaml('../../data/login.yaml')
print(res)6、运行 readYaml.py 文件查看结果是符合要求的(是需要的数据格式);
[('admin123', '123456'), ('admin123456', '123456'), ('admin123', '123456789'), ('admin123', '')]进程已结束,退出代码为 07、引入日志,优化 readYaml.py 文件;
像这种读取文件的操作最好是加上‘异常处理’和‘日志打印’;
import yaml
from util_tools.logs_util.recordlog import logsdef read_yaml(file_path):"""读取yaml文件的数据:param file_path: yaml文件路径:return: 返回列表类型,列表里面是元组数据,如:[('admin123','123456'),(),(),()......]"""try:data_list_tuple = []with open(file_path, 'r', encoding='utf-8') as file:# 添加这个 Loader=yaml.FullLoader 参数后不会在控制台输出警告信息data = yaml.load(file, Loader=yaml.FullLoader)for data_str in data:if data_str is not None:data_tuple = tuple(data_str.split(','))data_list_tuple.append(data_tuple)return data_list_tupleexcept Exception as e:logs.error(f'读取yaml文件异常,异常原因为:{e}')8、把读取 yaml 文件的写完了之后怎么在测试用例里面用到做参数化呢?
9、优化 test_login.py 文件;
1)、 导包引入读取 yaml 文件的 def read_yaml(file_path): 方法;
2)、使用 @pytest.mark.parametrize() 装饰器做参数化,第一个(参数)是接收后面一个可迭代参数(第二个参数)内容的参数,第一个参数 data(自定义名称),第二个参数 通过调用读取 yaml 文件 read_yaml() 方法,里面传路径文件参数;与读取 json 文件一样,这里更改读取方法即可,其他不动(自行更改代码);
import pytest
from selenium.webdriver.common.by import By
from time import sleep
from pageObject.login_page.login_page import LoginPage
# from util_tools.handle_data.operateJson import read_json
from util_tools.handle_data.readYaml import read_yamlclass TestLogin:# 使用参数化实现一条测试用例跑多种场景--可迭代对象里面有多少组数据就跑多少次测试用例@pytest.mark.parametrize('data', read_yaml('./data/login.yaml'))# 用一个 data(需与上面保持一致) 参数去接收参数化数据def test_login_success(self, get_driver, data):# 进行元组解包--通过两个参数去接收元组中的每一组数据username, password = data# 传浏览器对象--再把结果返回login_page = LoginPage(get_driver)# 直接调用页面类中的 login 操作--里面需要输入两个参数(参数化传两个参数)login_page.login(username, password)# 断言结果success_ele = get_driver.find_element(By.XPATH, '//*[@id="ECS_MEMBERZONE"]/font/font')assert success_ele != ''sleep(2)10、运行 run.py 主函数文件查看执行结果;
未完待续。。。
