自动包装/修饰所有最热的单元测试

2022-03-01 00:00:00 python pytest

问题描述

假设我有一个非常简单的日志装饰器:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} ran with args: {args}, and kwargs: {kwargs}")
        result = func(*args, **kwargs)
        return result
    return wrapper

我可以将此修饰器单独添加到每个pytest单元测试中:

@my_decorator
def test_one():
    assert True

@my_decorator
def test_two():
    assert 1

如何将此修饰器自动添加到每个pytest单元测试中,这样我就不必手动添加它了?如果我想要将其添加到文件中的每个单元测试中,该怎么办?还是在模块中?

我的用例是用SQL分析器包装每个测试函数,因此低效的ORM代码会引发错误。使用pytest fixture应该可以工作,但是我有数千个测试,所以自动应用包装器而不是将fixture添加到每个测试中会更好。此外,可能有一两个模块我不想评测,因此能够选择加入或选择退出整个文件或模块会很有帮助。


解决方案

如果您可以将逻辑移动到装置中(如问题所述),则只能使用在顶层conftest.py中定义的自动使用装置。

若要添加选择退出某些测试的可能性,您可以定义一个标记,该标记将添加到不应使用该装置的测试中,然后在该装置中检查该标记,例如:

conftest.py

import pytest

def pytest_configure(config):
    config.addinivalue_line(
        "markers",
        "no_profiling: mark test to not use sql profiling"
    )

@pytest.fixture(autouse=True)
def sql_profiling(request):
    if not request.node.get_closest_marker("no_profiling"):
        # do the profiling
    yield

test.py

import pytest

def test1():
    pass # will use profiling

@pytest.mark.no_profiling
def test2():
    pass # will not use profiling

正如@Hoefling所指出的,您还可以通过添加:

来禁用整个模块的灯具
pytestmark = pytest.mark.no_profiling

在模块中。这会将标记添加到所有包含的测试。

相关文章