You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pytest测试脚本外部获取已应用的pytestmark标记列表

你当前使用的pytest.mark._markers是pytest全局已注册标记的集合,并非当前运行测试的已应用标记列表,因此无法拿到预期结果。以下是符合你要求的实现方案,无需修改test_1.py的业务逻辑,也不需要使用fixture:

实现方案

只需要在项目根目录新增pytest自动加载的conftest.py配置文件,再调整module.py的内部逻辑即可。

第一步:编写conftest.py

实现两个核心能力:存储当前测试运行上下文、维持原有自定义标记的跳过逻辑

import pytest

# 全局变量存储当前正在运行的测试项
current_test_item = None
# 配置所有自定义跳过标记对应的触发条件,替代原有specific_case = pytest.mark.skipif写法
SKIP_CONFIG = {
    "specific_case": <CONDITION>, # 替换为你原来的跳过条件
    "specific_case_2": <CONDITION_2>,
    "specific_case_3": <CONDITION_3>,
    # 更多自定义标记按格式添加即可
}

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    """测试执行前存储当前测试项上下文"""
    global current_test_item
    current_test_item = item

@pytest.hookimpl(trylast=True)
def pytest_runtest_teardown(item):
    """测试执行后清空上下文避免污染"""
    global current_test_item
    current_test_item = None

@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(items):
    """给带自定义标记的用例自动添加跳过逻辑,无需修改原有测试代码"""
    for item in items:
        for mark_name, skip_condition in SKIP_CONFIG.items():
            if item.get_closest_marker(mark_name) and skip_condition:
                item.add_marker(pytest.mark.skip(reason=f"{mark_name} 触发跳过条件"))

第二步:调整module.py的属性逻辑

保持A类的外部调用接口完全不变,仅修改value属性的内部实现:

from conftest import current_test_item

class A():
    @property
    def value(self):
        # 非测试运行上下文直接返回默认值
        if not current_test_item:
            return 2
        # 收集当前测试所有层级的标记(模块级、类级、用例级)
        all_mark_names = set()
        # 读取模块级pytestmark
        if hasattr(current_test_item.module, "pytestmark"):
            module_marks = current_test_item.module.pytestmark
            module_marks = module_marks if isinstance(module_marks, list) else [module_marks]
            all_mark_names.update([m.name for m in module_marks])
        # 读取类级pytestmark(如果测试用例在测试类中)
        if current_test_item.cls and hasattr(current_test_item.cls, "pytestmark"):
            cls_marks = current_test_item.cls.pytestmark
            cls_marks = cls_marks if isinstance(cls_marks, list) else [cls_marks]
            all_mark_names.update([m.name for m in cls_marks])
        # 读取用例自身的标记
        all_mark_names.update([m.name for m in current_test_item.own_markers])
        # 按标记判断返回值
        if "specific_case" in all_mark_names:
            return 1
        return 2

可选兼容方案

如果你一定要保留原有specific_case = pytest.mark.skipif(<CONDITION>)的标记定义方式,只需要在定义时给每个标记添加自定义标识参数:

specific_case = pytest.mark.skipif(<CONDITION>, reason="xxx", custom_mark="specific_case")
specific_case_2 = pytest.mark.skipif(<CONDITION_2>, reason="xxx", custom_mark="specific_case_2")

然后在module.py的标记收集逻辑中补充对skipif标记的自定义参数判断即可:

# 补充到all_mark_names收集逻辑之后
for mark in current_test_item.iter_markers(name="skipif"):
    if "custom_mark" in mark.kwargs:
        all_mark_names.add(mark.kwargs["custom_mark"])

内容的提问来源于stack exchange,提问作者JaSON

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 04:36:03