如何为单个测试禁用 pytest 插件

How to disable pytest plugins for single tests

我安装了新的 pytest 插件 (pytest-catchlog==1.2.2),尽管我很喜欢它,但它破坏了我对日志记录模块的单元测试(例如 ValueError: I/O operation on closed file)。

我想为 test_logging.py 文件(甚至 class 或方法)禁用该插件,但我找不到任何相关信息。

到目前为止我发现的唯一选择是执行 pytest 两次:第一次 test_logging.py 仅禁用 catchlog (py.test -p no:catchlog test_logging.py),第二次所有其他测试文件。

如果我错过了 pytest 装饰器,或者任何其他在运行时禁用插件的方法,请告诉我。

您不能有选择地禁用选定测试的任意插件。插件在更早的阶段加载——当 pytest 启动时。插件实际上定义了 pytest 的作用和方式(即命令行选项、测试收集、过滤等)。

换句话说,当pytest执行测试时,再重新定义pytest的内部结构已经来不及了。

你最好的情况确实是用 @pytest.mark.nocatchlog 标记你的测试,然后分别执行它们:

pytest -m 'nocatchlog' -p no:catchlog  # problematic tests with no plugin
pytest -m 'not nocatchlog`             # all other tests

如果这些测试不受您的控制,即如果您不能添加标记,那么您只能按 -k test_logging-k 'not test_logging' 等表达式(即按其节点 ID 的一部分)进行过滤。


专门针对此 pytest-catchlog 插件,您可以按原样制作 same hooks,并从根记录器中删除其日志处理程序(假设未明确使用其他记录器):

conftest.py:

import pytest

def _disable_catchlog(item):
    logger = logging.getLogger()
    if item.catch_log_handler in logger.handlers:
        logger.handlers.remove(item.catch_log_handler)

@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_runtest_setup(item):
    _disable_catchlog(item)
    yield

@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_runtest_call(item):
    _disable_catchlog(item)
    yield

@pytest.hookimpl(hookwrapper=True, trylast=True)
def pytest_runtest_teardown(item):
    _disable_catchlog(item)
    yield