分享一个在实际测试过程中遇到的一个问题,想保留已有 Fixture 的setup逻辑,但临时跳过其teardown部分(且不修改原 Fixture 代码,为啥不修改呢,哎,别提了要修改那可是一大堆呀),可通过一个叫猴子补丁(Monkey Patching)结合 Pytest 的pytest_configure钩子实现
Pytest 的 Fixture 执行过程中,teardown逻辑(即yield之后的代码)由_pytest.fixtures.FixtureDef类的finish方法触发。我的核心思路是:在 Pytest 初始化阶段(通过pytest_configure钩子),用自定义的patched_finish方法 “替换” 原始的finish方法。当检测到目标 Fixture 时,直接返回不执行原始finish(跳过teardown);非目标 Fixture 则正常执行原逻辑,确保不能影响其它用例。
如图所示有一个myfixture的fixture
@pytest.fixture(autouse=True)
def my_fixture():
print("setup fixture")
yield
print("teardown fixture")正常跑用例,这货每次都要喊 "teardown fixture",现在想让它关键时刻装哑巴。孙行者,快收了神通吧!下面直接上神秘的咒语
# conftest.py
import pytest
@pytest.fixture(autouse=True)
def my_fixture():
print("setup fixture")
yield
print("teardown fixture")
# 保存原始方法
_original_fixture_finalizer = None
def patch_pytest_fixtures():
"""猴子补丁 pytest 的 fixture 执行逻辑"""
global _original_fixture_finalizer
from _pytest import fixtures
_original_fixture_finalizer = fixtures.FixtureDef.finish
def patched_finish(self, request):
fixture_name = getattr(self, 'func', None)
if fixture_name andhasattr(fixture_name, '__name__'):
if fixture_name.__name__ in ("my_fixture",):
print(f"跳过 fixture '{fixture_name.__name__}' 的 teardown")
return
return _original_fixture_finalizer(self, request)
fixtures.FixtureDef.finish = patched_finish
def pytest_configure(config):
patch_pytest_fixtures()实际执行结果如下

可以发现teardown部分没有被打印想恢复也是如此简单,注释掉pytest_configure即可

要了解更多猴子补丁用法的,查阅 MonkeyPatch 类的文档即可
#Pytest