likes
comments
collection
share

解锁 pytest_configure(config) 的神奇功能:个性化定制你的测试框架

作者站长头像
站长
· 阅读数 11

前言

def pytest_configure(config):
    config.addinivalue_line(
        'markers',
        'repeat(n): run the given test function `n` times.')
    ...

其实这里的pytest_configure也是一个钩子函数,那这个钩子函数有啥用?如何用?内部运行机制又是怎么样呢?带着这些疑问,我们一起来探索。

pytest_configure(config)是啥?

pytest_configure(config)pytest 中的一个钩子函数,它在pytest 运行前被调用一次,主要用于在测试运行之前进行配置和初始化工作。

我们看看源码中的定义:

@hookspec(historic=True)
def pytest_configure(config: "Config") -> None:
    """Allow plugins and conftest files to perform initial configuration.

    This hook is called for every plugin and initial conftest file
    after command line options have been parsed.

    After that, the hook is called for other conftest files as they are
    imported.

    .. note::
        This hook is incompatible with ``hookwrapper=True``.

    :param pytest.Config config: The pytest config object.
    """

pytest 配置文件或测试文件中定义 pytest_configure 函数,pytest 会自动调用它来处理一些常规的初始化、配置和插件注册工作。在 pytest 运行过程中,pytest_configure 函数可以通过config对象来访问 pytest 的各种配置信息和操作方法。

pytest_configure(config)如何使用?

定义全局变量或常量

我们配合conftest.py一起使用。在该模块中,我们可以定义一个pytest_configure(config)` 函数,并在其中定义一些全局变量或常量。我们看示例:

def pytest_configure(config):
    config.my_var = "hello world"

可以看到,我们定义了一个my_var变量,并赋值hello world。那在测试用例中该如何使用呢?我们继续看示例:

test_demo.py

def test_my_var(pytestconfig):
    assert pytestconfig.my_var == "hello world"

可以看到,我们使用内置的 pytestconfig fixture,来访问 config 对象,这条case运行后是通过的。

注册自定义插件或hook函数

pytest_configure 函数中,你可以注册自定义的插件或 hook函数,以便在 pytest 运行过程中进行调用和处理。看案例:

def pytest_configure(config):
    config.my_var = "hello world"
    config.pluginmanager.register(MyPlugin(), "my_plugin")

可以看到,我们使用 pytest 的插件管理器 pluginmanager 来注册一个名为MyPlugin 的插件。注册插件后,pytest 就可以根据插件的定义来进行相应的处理和调用。

test_demo.py

def test_mac(pytestconfig):
    assert pytestconfig.pluginmanager.hasplugin("my_plugin")

我们这里断言是否成功注册了插件,运行通过。

除了注册插件外,还可以在 pytest_configure 函数中注册各种 pytest 的 hook 函数,以便在测试运行过程中与其它插件或 fixture 进行交互和协作。例如:

def pytest_configure(config):
    config.addinivalue_line(
    "markers", "slow: mark test as slow to run"
    )

在上述代码中,我们使用 config 对象的 addinivalue_line 方法来添加一个名为 "slow" 的标记,来标识某些测试用例需要特殊处理或忽略。

配置 pytest 各种参数和选项

在 pytest_configure 函数中,你可以配置 pytest 的各种参数和选项,以适应不同的测试需求和场景。例如:

def pytest_configure(config):
    config.addinivalue_line("markers", "unit: mark a test as a unit test")
    config.addinivalue_line("markers", "integration: mark a test as an integration test")
    config.addoption("--my-option", action="store",
        default="default-value", help="my option's help text")

在上述代码中,我们使用 config 对象的 addinivalue_line 和 addoption 方法分别添加了两个 marker 标记(用于标识测试用例)和一个自定义选项。这些配置信息可以在 pytest 运行时通过命令行参数进行覆盖或修改。

案例实现

我们现在想要实现一个需求:编写一个自定义插件,根据不同的操作系统或网络环境来选择不同的测试用例或配置参数。如何实现呢?

conftest.py

实现插件功能:

class OSPlugin:
    def pytest_collection_modifyitems(self, config, items):
        os_name = platform.system()
        if os_name == 'Windows':
            items[:] = [item for item in items if 'windows' in item.name]
        elif os_name == 'Linux':
            items[:] = [item for item in items if 'linux' in item.name]
        elif os_name == 'Darwin':
            items[:] = [item for item in items if 'mac' in item.name]
        else:
            # 对于其他操作系统,跳过所有测试用例
            items.clear()

    def pytest_configure(self, config):
        print(f"Running tests on {platform.system()}")

这段代码,我们创建了一个名为 OSPlugin 的自定义插件类。它实现了 pytest_collection_modifyitems 方法,在收集测试用例之后修改测试用例项。根据当前操作系统的不同,我们可以选择性地保留或跳过特定的测试用例。

我们还实现了 pytest_configure 方法,用于打印正在运行测试的操作系统信息。

注册自定义插件:

def pytest_configure(config):
    config.pluginmanager.register(OSPlugin(), "os_plugin")

测试case:

test_demo.py

def test_windows_only():
    assert True

def test_linux_only():
    assert True

def test_mac_case():
    assert True

笔者是mac系统,执行结果如下:

Running tests on Darwin
============================= test session starts ==============================
collecting ... Darwin
collected 3 items

test_demo.py::test_mac_case 

============================== 1 passed in 0.13s ===============================

可以看到,当你运行这些测试用例时,根据不同的操作系统,将会选择性地执行特定测试用例或跳过所有测试用例。

运行机制

到这里应该能够正确使用该函数了,我们再看一下它的运行机制是怎样的呢?

这个插件钩子函数的主要作用是对 config 对象进行配置,其中 config 是一个 pytest 的配置对象,提供了对 pytest 运行过程中的配置项进行读取和修改的接口。

  1. pytest 启动时,会自动加载所有已注册的插件。
  2. pytest 开始配置过程,遍历已加载的插件,依次调用每个插件的 pytest_configure 方法。
  3. 通过调用 pytest_configure(config) 方法,插件可以访问和修改 config 对象来进行配置。
  4. 插件可以使用 config. 前缀来访问或修改 config 对象的属性和方法。

最后

pytest_configure(config) 钩子函数是一个非常灵活和强大的 pytest 扩展机制,可以用来进行各种初始化、配置、插件注册等工作。可以使用 pytest_configure 函数来处理各种复杂的测试需求和场景,从而提高测试代码的可读性和可维护性。很大三方插件都使用了该钩子函数,比如开头提到的pytest_repeat插件。另外,我们在案例实现中使用了pytest_collection_modifyitems()钩子函数,我们之后会写一篇文章来讲解该钩子函数的使用原理。

转载自:https://juejin.cn/post/7280747221509816374
评论
请登录