前言
在深入理解 pytest-repeat 插件的工作原理这篇文章中,我们看到pytest_repeat
源码中有这样一段
scss
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
运行前被调用一次,主要用于在测试运行之前进行配置和初始化工作。
我们看看源码中的定义:
python
@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)` 函数,并在其中定义一些全局变量或常量。我们看示例:
arduino
def pytest_configure(config):
config.my_var = "hello world"
可以看到,我们定义了一个my_var
变量,并赋值hello world
。那在测试用例中该如何使用呢?我们继续看示例:
test_demo.py
python
def test_my_var(pytestconfig):
assert pytestconfig.my_var == "hello world"
可以看到,我们使用内置的 pytestconfig
fixture,来访问 config
对象,这条case
运行后是通过的。
注册自定义插件或hook
函数
在 pytest_configure
函数中,你可以注册自定义的插件或 hook
函数,以便在 pytest
运行过程中进行调用和处理。看案例:
arduino
def pytest_configure(config):
config.my_var = "hello world"
config.pluginmanager.register(MyPlugin(), "my_plugin")
可以看到,我们使用 pytest
的插件管理器 pluginmanager
来注册一个名为MyPlugin
的插件。注册插件后,pytest 就可以根据插件的定义来进行相应的处理和调用。
test_demo.py
python
def test_mac(pytestconfig):
assert pytestconfig.pluginmanager.hasplugin("my_plugin")
我们这里断言是否成功注册了插件,运行通过。
除了注册插件外,还可以在 pytest_configure 函数中注册各种 pytest 的 hook 函数,以便在测试运行过程中与其它插件或 fixture 进行交互和协作。例如:
scss
def pytest_configure(config):
config.addinivalue_line(
"markers", "slow: mark test as slow to run"
)
在上述代码中,我们使用 config 对象的 addinivalue_line 方法来添加一个名为 "slow" 的标记,来标识某些测试用例需要特殊处理或忽略。
配置 pytest 各种参数和选项
在 pytest_configure 函数中,你可以配置 pytest 的各种参数和选项,以适应不同的测试需求和场景。例如:
scss
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
实现插件功能:
ini
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
方法,用于打印正在运行测试的操作系统信息。
注册自定义插件:
scss
def pytest_configure(config):
config.pluginmanager.register(OSPlugin(), "os_plugin")
测试case
:
test_demo.py
python
def test_windows_only():
assert True
def test_linux_only():
assert True
def test_mac_case():
assert True
笔者是mac
系统,执行结果如下:
ini
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 运行过程中的配置项进行读取和修改的接口。
- 当
pytest
启动时,会自动加载所有已注册的插件。 pytest
开始配置过程,遍历已加载的插件,依次调用每个插件的pytest_configure
方法。- 通过调用
pytest_configure(config)
方法,插件可以访问和修改config
对象来进行配置。 - 插件可以使用
config.
前缀来访问或修改config
对象的属性和方法。
最后
pytest_configure(config)
钩子函数是一个非常灵活和强大的 pytest 扩展机制,可以用来进行各种初始化、配置、插件注册等工作。可以使用 pytest_configure
函数来处理各种复杂的测试需求和场景,从而提高测试代码的可读性和可维护性。很大三方插件都使用了该钩子函数,比如开头提到的pytest_repeat
插件。另外,我们在案例实现中使用了pytest_collection_modifyitems()
钩子函数,我们之后会写一篇文章来讲解该钩子函数的使用原理。