pytest 7.0 起 request.applymarker 已被彻底移除,因其违背静态标记设计原则;应改用 @pytest.mark 装饰器、pytest.skip() 或 skipif 等官方推荐方式控制测试行为。

pytest 中 request.applymarker 已被移除,不能用了
从 pytest 7.0 开始,request.applymarker 已被彻底删除。你如果在新版本中调用它,会直接报错:AttributeError: 'FixtureRequest' object has no attribute 'applymarker'。这不是拼写错误或路径问题,是 API 彻底废弃——官方认为动态打标记属于反模式,容易让测试行为变得隐晦难维护。
替代方案:用 pytest.mark 装饰器 + 条件逻辑
真正可控、可读、被 pytest 官方支持的方式,是在定义测试函数时就通过装饰器声明标记,必要时结合 Python 的条件表达式或函数工厂生成带标记的测试。
- 静态场景(推荐):直接用
@pytest.mark.slow、@pytest.mark.parametrize等标准装饰器 - 动态场景(如根据环境变量决定是否标记):用
pytest_configure钩子或自定义插件预注册标记,再配合@pytest.mark使用 - 运行时“模拟”动态标记:不真改标记,而是在 fixture 或 setup 中跳过测试,例如
if not should_run_slow(): pytest.skip("skipped by config")
示例:根据环境变量控制是否启用 slow 标记
# conftest.py
import pytest
<p>def pytest_configure(config):
if config.getoption("--runslow", default=False):
config.addinivalue_line("markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')")
else:</p><h1>不注册标记,但测试里仍写了 @pytest.mark.slow?pytest 会警告,但不报错</h1><pre class="brush:php;toolbar:false;"> pass
然后在测试中写:
@pytest.mark.slow
def test_heavy_computation():
...
运行时加 --runslow 才执行它。
为什么不用 applymarker 是对的
标记(marker)本质是 pytest 的静态元数据,用于筛选、分组、跳过,不是运行时状态。如果允许在 fixture 里动态添加,会导致:
- 同一个测试函数在不同 fixture 组合下可能有不同标记,难以预测
-m行为 - pytest 收集阶段(collection)已结束,标记变更无法影响收集结果,只对后续执行阶段无效
- 与 xdist 并行执行冲突:worker 进程无法同步运行时修改的标记
- IDE 和 pytest 插件(如 PyCharm 的测试导航)依赖静态标记,动态添加会让它们失效
真需要运行时控制?用 pytest.skip() 或 pytest.xfail()
如果你的本意其实是“某些条件下跳过某个测试”,而不是“给它打个标记再让其他逻辑去处理”,那就别绕弯子:
- 在测试函数开头判断条件,调用
pytest.skip("reason") - 在 fixture 中判断并跳过(注意:fixture 中跳过会影响所有依赖它的测试)
- 用
pytest.mark.skipif(condition, reason="...")做声明式跳过,更清晰
示例:
@pytest.mark.skipif("os.getenv('CI') == 'true'", reason="skip on CI")
def test_local_only():
...
标记不是开关,它是标签。想控制执行逻辑,就用跳过、参数化、钩子或配置驱动——别试图在运行时给测试“贴新标签”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











