pytest_collection_modifyitems钩子函数的具体使用方法

345 阅读5分钟

pytest_collection_modifyitemspytest 的一个钩子函数,用于在测试用例收集完成后修改或操作测试用例列表。它允许你在运行测试之前对收集到的测试用例进行排序、过滤、动态添加标记等操作。

下面是这个钩子函数的详细解释和常见用法:


1. pytest_collection_modifyitems 的基本定义

钩子函数的签名如下:

def pytest_collection_modifyitems(config, items):
    """
    pytest_collection_modifyitems 是 pytest 在收集到所有测试用例后调用的钩子。
    :param config: pytest 的配置信息对象,可以访问命令行参数等
    :param items: 收集到的测试用例列表(pytest.Item 对象)
    """
  • config:pytest 的配置信息对象,可以通过它访问命令行参数(如 config.getoption)或配置文件。
  • items:pytest 收集到的测试用例列表,包含所有待运行的测试用例。你可以对该列表执行操作(如排序、筛选、添加标记等)。

2. 常见用法

2.1 修改测试用例的执行顺序

可以通过对 items 列表进行排序来改变测试用例的执行顺序。

示例:按测试用例名称排序

def pytest_collection_modifyitems(config, items):
    # 按测试用例名称排序
    items.sort(key=lambda item: item.name)

示例:按自定义标记排序

如果你为测试用例添加了自定义标记(如 @pytest.mark.order),可以根据标记的值对测试用例进行排序:

def pytest_collection_modifyitems(config, items):
    # 按标记顺序排序
    items.sort(key=lambda item: item.get_closest_marker("order").args[0] if item.get_closest_marker("order") else 0)

在测试代码中:

import pytest

@pytest.mark.order(2)
def test_case_2():
    assert True

@pytest.mark.order(1)
def test_case_1():
    assert True

@pytest.mark.order(3)
def test_case_3():
    assert True

运行后,测试用例会按照 order 标记的顺序执行。


2.2 动态添加标记

可以根据测试用例的名称、参数或其他条件动态为测试用例添加标记。

示例:为特定名称的用例添加标记

def pytest_collection_modifyitems(config, items):
    for item in items:
        if "slow" in item.name:  # 如果用例名称中包含 "slow"
            item.add_marker(pytest.mark.slow)

运行时,你可以使用 pytest -m slow 只运行这些标记的用例。


2.3 过滤测试用例

如果需要在运行前动态过滤掉某些测试用例,可以直接从 items 列表中移除它们。

示例:过滤掉所有名称中包含 "skip" 的测试用例

def pytest_collection_modifyitems(config, items):
    items[:] = [item for item in items if "skip" not in item.name]

运行时,这些包含 skip 的测试用例将不会被执行。


2.4 根据命令行参数动态筛选用例

可以通过 config.getoption 读取命令行参数来动态筛选测试用例。

示例:只运行包含某关键字的用例

def pytest_addoption(parser):
    parser.addoption("--keyword", action="store", default=None, help="只运行包含指定关键字的测试用例")

def pytest_collection_modifyitems(config, items):
    keyword = config.getoption("--keyword")
    if keyword:
        # 过滤出名称包含关键字的用例
        items[:] = [item for item in items if keyword in item.name]

运行时指定关键字:

pytest --keyword test

2.5 动态标记参数化测试用例

对于参数化的测试用例,可以在收集时根据参数动态添加标记。

示例:为测试用例添加参数相关的标记

def pytest_collection_modifyitems(config, items):
    for item in items:
        if hasattr(item, "callspec"):
            params = item.callspec.params
            # 根据参数值动态添加标记
            if "username" in params and params["username"] == "admin":
                item.add_marker(pytest.mark.admin)

在测试代码中:

import pytest

@pytest.mark.parametrize("username", ["user", "admin"])
def test_login(username):
    assert username in ["user", "admin"]

运行时,pytest -m admin 会只运行参数为 "admin" 的测试用例。


2.6 为测试用例添加自定义元数据

可以动态为测试用例添加元数据,方便后续分析或扩展。

示例:为用例添加描述信息

def pytest_collection_modifyitems(config, items):
    for item in items:
        if "login" in item.name:
            item.user_properties.append(("description", "Login related test"))
        elif "payment" in item.name:
            item.user_properties.append(("description", "Payment related test"))

在测试代码中,可以通过 item.user_properties 访问这些元数据。


2.7 按 YML 文件中的字段动态标记用例

如果测试用例来源于 YML 文件,可以在收集时根据 YML 文件中的字段动态为用例添加标记。

示例:基于 YML 文件的 marks 字段添加标记

假设 YML 文件如下:

test_cases:
  - name: "test_login_success"
    marks: ["smoke", "regression"]
  - name: "test_login_failure"
    marks: ["regression"]

测试代码:

import pytest

def pytest_collection_modifyitems(config, items):
    # 加载 YML 文件
    import yaml
    with open("test_cases.yml", "r") as f:
        test_cases = yaml.safe_load(f)["test_cases"]
    
    # 为用例动态添加标记
    for item in items:
        for case in test_cases:
            if case["name"] == item.name:
                for mark in case.get("marks", []):
                    item.add_marker(pytest.mark.__getattr__(mark))

然后可以用 pytest -m smokepytest -m regression 来选择性运行用例。


3. 注意事项

  1. items 是可变列表: 对 items 列表的修改会直接影响 pytest 收集到的测试用例。可以通过以下方式操作:

    • items.sort():排序
    • items[:] = [...]:替换整个列表
    • items.remove(item):移除特定用例
  2. 避免误操作

    • 不要删除 pytest 本身的系统关键字或对非测试用例的对象操作。
  3. 与其他插件的兼容性: 如果使用了其他插件(如 pytest-order 等),确保 pytest_collection_modifyitems 的逻辑不会与插件冲突。


4. 总结

pytest_collection_modifyitems 是非常强大的钩子,可以帮助你在测试用例收集阶段动态调整用例的行为。它的常见用法包括:

  • 修改测试用例执行顺序。
  • 动态添加标记(Mark)。
  • 过滤或筛选测试用例。
  • 根据参数化动态标记用例。
  • 根据外部数据文件(如 YML)动态操作用例。

通过合理使用这个钩子,可以使测试用例的管理更加灵活和智能化!