Bootstrap

pytest如何实现yml测试用例的Mark功能

pytest 中,如果测试用例是从 YML 文件中加载的,你可以动态地为这些用例添加 Mark,从而实现对 YML 测试用例的分类和控制。以下是实现 YML 测试用例的 Mark 功能的完整方法:


1. 场景描述

假设测试用例是从一个 YML 文件中加载的,你希望能够:

  • 为每个用例动态添加 Mark,如 smokeregressionperformance 等。
  • 根据 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 的测试

运行属于 smokeregression 的测试:

pytest -m "smoke or regression" -v

运行同时包含 smokeregression 的测试:

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):
    # 测试逻辑
    ...

总结

通过上述方法,实现了以下功能:

  1. 在 YML 文件中定义 Mark,通过 marks 字段分类测试用例。
  2. 动态添加 Mark,使用 request.node.add_marker 在运行时为测试用例添加标记。
  3. 根据 Mark 控制测试执行,可以通过 pytest -m 灵活运行或排除特定类型的用例。
  4. 优化测试用例收集,通过 pytest_collection_modifyitems 钩子或过滤机制进一步提升灵活性。

这种方式可以很好地管理和分类 YML 测试用例,同时保持代码简洁且易于扩展。

;