在 pytest 中,如果测试用例是从 YML 文件中加载的,你可以动态地为这些用例添加 Mark,从而实现对 YML 测试用例的分类和控制。以下是实现 YML 测试用例的 Mark
功能的完整方法:
1. 场景描述
假设测试用例是从一个 YML 文件中加载的,你希望能够:
- 为每个用例动态添加
Mark
,如smoke
、regression
、performance
等。 - 根据
Mark
选择性运行某些类型的用例。 - 在 YML 文件中定义 Mark 信息。
2. 实现步骤
Step 1: 定义 YML 文件,包含 Mark 信息
在 YML 文件中为每个用例添加一个 marks
字段,用于标记该用例的分类。
示例 YML 文件 (test_cases.yml
):
test_cases:
- case_id: 1
description: "登录成功测试"
marks: ["smoke", "regression"] # 用例属于 smoke 和 regression 分类
input:
username: "user1"
password: "pass1"
expected:
status_code: 200
message: "登录成功"
- case_id: 2
description: "登录失败测试"
marks: ["regression"] # 用例属于 regression 分类
input:
username: "user2"
password: "wrong_pass"
expected:
status_code: 401
message: "用户名或密码错误"
- case_id: 3
description: "性能测试用例"
marks: ["performance"] # 用例属于 performance 分类
input:
username: "user3"
password: "pass3"
expected:
status_code: 200
message: "性能测试完成"
Step 2: 加载 YML 文件并解析用例
使用 PyYAML
模块加载 YML 文件,并提取测试用例数据。
示例代码:读取 YML 文件:
import yaml
# 加载 YML 测试用例
def load_test_cases(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return yaml.safe_load(file)["test_cases"]
Step 3: 动态为 YML 用例添加 Mark
在测试代码中,可以通过 pytest.mark
动态为从 YML 文件加载的测试用例添加 Mark。例如,提取每个用例的 marks
字段,并将其添加到 pytest 的 request.node
。
完整测试代码:
import pytest
import yaml
# 加载 YML 测试用例
def load_test_cases(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return yaml.safe_load(file)["test_cases"]
# 加载测试数据
test_cases = load_test_cases("test_cases.yml")
# 参数化测试用例
@pytest.mark.parametrize("case", test_cases)
def test_yml_cases(case, request):
# 动态添加 Mark
for mark in case.get("marks", []):
request.node.add_marker(getattr(pytest.mark, mark))
# 模拟测试逻辑
print(f"执行用例: {case['description']}")
username = case["input"]["username"]
password = case["input"]["password"]
# 模拟登录逻辑
response = simulate_login(username, password)
# 验证结果
assert response["status_code"] == case["expected"]["status_code"]
assert response["message"] == case["expected"]["message"]
# 模拟登录逻辑
def simulate_login(username, password):
if username == "user1" and password == "pass1":
return {"status_code": 200, "message": "登录成功"}
elif username == "user2" and password == "wrong_pass":
return {"status_code": 401, "message": "用户名或密码错误"}
else:
return {"status_code": 200, "message": "性能测试完成"}
Step 4: 根据 Mark 运行测试
运行所有测试
直接运行所有测试:
pytest -v
运行特定 Mark 的测试
运行特定 Mark 的测试(例如 smoke
):
pytest -m smoke -v
运行多个 Mark 的测试
运行属于 smoke
或 regression
的测试:
pytest -m "smoke or regression" -v
运行同时包含 smoke
和 regression
的测试:
pytest -m "smoke and regression" -v
运行排除某些 Mark 的测试
运行除 performance
外的所有测试:
pytest -m "not performance" -v
3. 整体运行效果
假设我们运行以下命令:
pytest -m smoke -v
输出将显示仅运行被标记为 smoke
的测试用例:
test_example.py::test_yml_cases[登录成功测试] PASSED
如果运行:
pytest -m "regression" -v
输出将显示运行所有被标记为 regression
的测试用例:
test_example.py::test_yml_cases[登录成功测试] PASSED
test_example.py::test_yml_cases[登录失败测试] PASSED
4. 使用 pytest.ini 注册自定义 Mark
为了避免未注册标记的警告,建议在 pytest.ini
文件中注册自定义的 Mark。
示例 pytest.ini
文件:
[pytest]
markers =
smoke: 标记冒烟测试
regression: 标记回归测试
performance: 标记性能测试
5. 进一步优化
优化 1: 使用 pytest 的钩子自动分类
使用 pytest_collection_modifyitems
钩子,可以在用例收集阶段自动添加 Mark,而不需要在每个测试函数中手动添加。
def pytest_collection_modifyitems(config, items):
for item in items:
case = item.callspec.params.get("case", {})
marks = case.get("marks", [])
for mark in marks:
item.add_marker(getattr(pytest.mark, mark))
优化 2: 动态过滤 YML 用例
如果只想加载特定 Mark 的测试用例,可以在参数化之前过滤 test_cases
:
# 只加载包含 smoke 的用例
filtered_cases = [case for case in test_cases if "smoke" in case.get("marks", [])]
@pytest.mark.parametrize("case", filtered_cases)
def test_yml_cases(case):
# 测试逻辑
...
总结
通过上述方法,实现了以下功能:
- 在 YML 文件中定义 Mark,通过
marks
字段分类测试用例。 - 动态添加 Mark,使用
request.node.add_marker
在运行时为测试用例添加标记。 - 根据 Mark 控制测试执行,可以通过
pytest -m
灵活运行或排除特定类型的用例。 - 优化测试用例收集,通过
pytest_collection_modifyitems
钩子或过滤机制进一步提升灵活性。
这种方式可以很好地管理和分类 YML 测试用例,同时保持代码简洁且易于扩展。