8:YAML 语法
承接前面 Pytest 框架全系列知识点(用例规则、前后置、断言、参数化、Fixture),本篇讲解YAML,是自动化项目实现「代码与用例数据分离」最主流配置文件,接口自动化 90% 项目都会用 yml 存储接口地址、请求参数、测试用例数据,搭配 Pytest+Fixture + 参数化实现标准自动化项目架构。
一、YAML 基础概念 & 优势
1. 什么是 YAML
YAML 全称:YAML Ain't Markup Language(YAML 不是标记语言),是面向人类可读的数据序列化格式,后缀.yml/.yaml,自动化领域统一简写.yml,用来替代 JSON/XML 做配置、用例数据存储。
2. YAML 对比 JSON/XML 核心优势
- 极简无冗余符号:去掉 JSON 的
{}、""、逗号,靠缩进区分层级,编写效率更高; - 天然适配配置场景:注释友好(
#单行注释),JSON 不支持注释,配置文件可读性碾压 JSON; - 缩进逻辑和 Python 一致,Python 开发上手零门槛;
- 原生支持列表、字典、布尔、数字、嵌套结构,完美匹配接口 JSON 返回格式。
3. YAML 硬性语法规范(避坑必看)
- 严格区分大小写:
Name和name是两个不同 key; - 禁止使用 Tab 制表符:只能用空格缩进(一般 2 空格),编辑器 Tab 自动转空格;
- 缩进决定层级关系:同层级缩进空格数必须一致;
#代表单行注释,不能行内注释。
在线工具:JSON 一键转 YAML:https://www.jashtool.com/json/to-yaml(复杂结构快速转换)
二、YAML 全数据类型语法详解(对标 JSON,附对照代码)
yml 支持字符串、数字、布尔、列表、字典、嵌套组合6 种核心数据,下面每种格式附带 yml 写法 + 等效 JSON,适配接口参数场景。
1. 基础键值对(对标 JSON 对象键值)
yaml
# yml写法 username: admin password: 123456等效 JSON:
{"username":"admin","password":"123456"}2. 数值类型(int 整数 /float 浮点数)
yaml
int_num: 99 float_num: 123.456json
{"int_num":99,"float_num":123.456}3. 布尔值(true/false,小写,自动识别 bool 类型)
yaml
is_login: true is_delete: falsejson
{"is_login":true,"is_delete":false}4. 字符串(默认不用引号,特殊字符才加双引号)
yaml
# 普通字符串无需引号 title: 用户登录接口 # 含特殊符号用双引号 desc: "接口地址:/api/login,请求方式POST"json
{"title":"用户登录接口","desc":"接口地址:/api/login,请求方式POST"}5. 列表(短横线-+ 空格开头,一行一个元素)
yaml
# 接口参数列表 params_list: - admin - root - test01json
{"params_list":["admin","root","test01"]}6. 嵌套字典(缩进实现子键,接口返回嵌套 json 最常用)
yaml
user_info: uid: 1001 name: 张三 phone: 13800138000json
{"user_info":{"uid":1001,"name":"张三","phone":"13800138000"}}7. 列表 + 字典混合嵌套(接口用例标准格式!自动化高频)
最常用:一条用例 = 字典,多条用例放入列表
yaml
# 登录接口多组测试用例 login_case: - case_name: 正确账号密码登录 req_data: username: admin password: 123456 expect_code: 200 - case_name: 密码错误登录 req_data: username: admin password: 654321 expect_code: 401上面是接口自动化 yml 用例标准模板,后续结合 pytest 参数化直接读取批量执行。
三、PyYAML 环境安装
Python 使用PyYAML库读写 yml 文件,固定版本6.0.1避免版本 API 差异:
# 安装指定版本 pip install PyYAML==6.0.1四、PyYAML 核心:yml 读取 & 写入代码封装
封装通用工具类:read_yaml读取、write_yaml新增写入、clear_yaml清空文件,自动化项目通用工具函数。
import yaml # 1. 读取yml指定key数据 def read_yaml(file_path, key=None): """ :param file_path: yml文件路径 :param key: 需要读取的键,不传则返回全部数据 """ with open(file_path, encoding="utf-8", mode="r") as f: data = yaml.safe_load(f) # safe_load安全加载,规避恶意代码注入 if key: return data.get(key) return data # 2. 追加/写入yml文件(a+追加,w覆盖) def write_yaml(file_path, data): with open(file_path, encoding="utf-8", mode="a+") as f: yaml.safe_dump(data, stream=f, allow_unicode=True) # allow_unicode=True:中文不乱码,必加参数! # 3. 清空yml文件内容 def clear_yaml(file_path): with open(file_path, encoding="utf-8", mode="w") as f: f.truncate() # 测试用例 def test_yml_opt(): # 写入数据 test_data = {"str": "12345"} write_yaml("test.yml", test_data) # 读取数据 res = read_yaml("test.yml", "str") print("读取结果:", res) # clear_yaml("test.yml") # 按需清空关键参数
allow_unicode=True:不加会出现中文转 unicode 编码(\u5f20\u4e09),存储中文 yml 必带。
五、实战 1:Pytest+YAML 实现接口用例数据分离(项目落地)
步骤 1:新建api_case.yml,存储登录接口多组用例
login_api: - case_title: 正常登录 url: https://jsonplaceholder.typicode.com/users/1 method: GET expect_uid: 1 - case_title: 异常ID查询 url: https://jsonplaceholder.typicode.com/users/999 method: GET expect_uid: None步骤 2:pytest 参数化读取 yml,自动批量执行用例
import pytest import requests from common.yaml_util import read_yaml # 导入上面封装的读取函数 # 读取yml内登录用例 case_data = read_yaml("api_case.yml", "login_api") # 参数化批量生成用例 @pytest.mark.parametrize("case", case_data) def test_login_api(case): # 从yml取出接口参数 url = case["url"] expect = case["expect_uid"] res = requests.get(url) # 结合之前assert断言 if res.status_code ==200: actual_uid = res.json()["id"] assert actual_uid == expect, f"{case['case_title']}校验失败,预期{expect},实际{actual_uid}" else: assert expect is None执行效果:yml 里 2 组用例自动生成 2 条 pytest 用例,新增测试场景只需要修改 yml
不用改动 Python 代码,完美实现数据代码分离。
六、实战 2:Fixture+YAML 全局配置(conftest 读取全局环境配置)
1. 项目根目录config.yml(全局环境配置:域名、请求头)
yaml
base_url: https://jsonplaceholder.typicode.com headers: Content-Type: application/json token: test_token_0012. conftest.py 全局 fixture,全项目任意用例直接引用
import pytest from common.yaml_util import read_yaml @pytest.fixture(scope="session") def global_config(): # 项目全局读取配置yml config = read_yaml("config.yml") return config3. 任意测试用例直接调用全局配置
def test_post_query(global_config): base = global_config["base_url"] header = global_config["headers"] url = f"{base}/posts/1" res = requests.get(url,headers=header) assert res.status_code ==200七、PyYAML 常用避坑总结
- 中文乱码:safe_dump必须加allow_unicode=True;
- 缩进报错:统一 2 空格缩进,全程禁用 Tab;
- 加载文件空值:yml 空行、格式错误会导致safe_load返回 None;
- 安全规范:优先用yaml.safe_load(),禁止yaml.load()(老版本存在代码注入漏洞);
- 列表横线-后面必须带空格,-admin写法非法,正确- admin。
八、拓展:自动化项目 yml 分层规范(企业项目目录)
自动化项目/ ├─ config/ │ └─ env.yml # 全局环境配置(域名、数据库地址) ├─ testcase/ │ ├─ login_case.yml # 登录模块用例 │ └─ user_case.yml # 用户模块用例 ├─ common/ │ └─ yaml_tool.py # 封装yml读写工具类 └─ conftest.py # fixture全局读取配置