玩命加载中 . . .

pytest hook系列之pytest_load_initial_conftests


概述

pytest_load_initial_conftestspytest 提供的一个钩子函数,专门用来在测试开始之前加载最早的 conftest.py 文件。它在 pytest 启动的早期阶段被调用,主要用于在加载初始 conftest.py 文件之前和之后进行一些定制操作。通过这个钩子,我们可以在测试运行之前进行一些前置操作,比如动态配置环境、预处理某些文件或目录等。

使用场景

这个钩子函数可以用在以下几个场景:

  • 在测试运行之前动态添加或修改conftest.py文件路径。

  • 在测试框架加载初始配置之前执行某些操作(例如,设置环境变量、初始化日志系统等)。

  • 定制conftest.py文件的搜索路径,适配特定的项目结构或需求。

参数

  • early_config: 一个Config对象,包含 pytest最早的配置和命令行选项。

  • args: 命令行参数列表,可以用来决定如何加载conftest.py文件。

示例代码

以下是一个完整的示例代码及其详细注释,展示了如何使用 pytest_load_initial_conftests 钩子函数。

假设目录结构如下:

├── conftest.py
├── custom
│   ├── conftest.py
│   └── __init__.py
├── my_pytest_plugin.py
├── pytest.ini
└── tests
    ├── __init__.py
    └── test_example.py

创建插件模块

# my_pytest_plugin.py
import os
import importlib.util

def pytest_load_initial_conftests(early_config, args):
    """
    Pytest 钩子函数:加载初始 conftest.py 文件

    参数:
        early_config: Config 对象,包含 Pytest 的早期配置和命令行选项
        args: 命令行参数列表
    """
    print("Initial command line arguments:", args)

    # 设置环境变量
    os.environ["TEST_ENV"] = "true"
    print("Environment variable TEST_ENV set to 'true'")

    # 动态加载 conftest.py
    custom_conftest_dir = "/root/test/hook/custom"
    custom_conftest_path = os.path.join(custom_conftest_dir, "conftest.py")

    if os.path.isfile(custom_conftest_path):
        spec = importlib.util.spec_from_file_location("custom_conftest", custom_conftest_path)
        custom_conftest = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(custom_conftest)
        print(f"Loaded custom conftest from {custom_conftest_path}")

# 确保模块导入时出发调试打印
print("my_pytest_plugin module imported")

配置pytest.ini文件

# pytest.ini
[pytest]
addopts = -p my_pytest_plugin

创建示例conftest.py文件

为了验证动态加载的效果,我们在自定义路径下创建一个示例conftest.py文件。

文件路径: /path/to/custom/conftest/conftest.py # 请根据实际情况修改

print("Custom conftest.py loaded successfully")

def pytest_configure(config):
    print("Custom conftest.py pytest_configure called")

创建项目根目录下conftest.py文件

# 文件路径: 项目根目录/conftest.py

pytest_plugins = ["my_pytest_plugin"]

def pytest_configure(config):
    print("conftest.py has been loaded.")

创建测试文件

我们创建一个测试文件,验证测试环境变量是否被正确设置。

文件路径: 项目根目录/tests/test_example.py

import os

def test_env_variable():
    assert os.getenv("TEST_ENV") == "true"

运行和验证

在项目根目录运行 pytest:

PYTHONPATH=. pytest

输出结果

控制台应显示如下信息,表示插件成功加载,环境变量设置正确,并且自定义的conftest.py文件被正确加载:

root@Gavin:~/test/hook# PYTHONPATH=. pytest -s -v
my_pytest_plugin module imported
Initial command line arguments: ['-p', 'my_pytest_plugin', '-s', '-v']
Environment variable TEST_ENV set to 'true'
Custom conftest.py loaded successfully
Loaded custom conftest from /root/test/hook/custom/conftest.py
conftest.py has been loaded.
================================================================================================================== test session starts ==================================================================================================================
platform linux -- Python 3.11.6, pytest-8.0.2, pluggy-1.5.0 -- /usr/bin/python3
cachedir: .pytest_cache
Test order randomisation NOT enabled. Enable with --random-order or --random-order-bucket=<bucket_type>
sensitiveurl: .*
metadata: {'Python': '3.11.6', 'Platform': 'Linux-6.5.0-35-generic-x86_64-with-glibc2.38', 'Packages': {'pytest': '8.0.2', 'pluggy': '1.5.0'}, 'Plugins': {'cov': '4.1.0', 'order': '1.2.0', 'random-order': '1.1.1', 'tornasync': '0.6.0.post2', 'check': '2.2.2', 'instafail': '0.5.0', 'allure-pytest': '2.13.2', 'asyncio': '0.23.6', 'selenium': '4.1.0', 'xdist': '3.5.0', 'variables': '3.1.0', 'rerunfailures': '13.0', 'html': '4.1.1', 'progress': '1.2.5', 'metadata': '3.0.0', 'twisted': '1.14.1', 'picked': '0.5.0', 'anyio': '4.3.0', 'Faker': '24.0.0', 'trio': '0.8.0', 'repeat': '0.9.3', 'base-url': '2.1.0', 'dependency': '0.6.0', 'dotenv': '0.5.2', 'timeout': '2.2.0'}, 'JAVA_HOME': '/usr/lib/jdk1.8.0_171', 'Base URL': '', 'Driver': None, 'Capabilities': {}}
rootdir: /root/test/hook
configfile: pytest.ini
plugins: cov-4.1.0, order-1.2.0, random-order-1.1.1, tornasync-0.6.0.post2, check-2.2.2, instafail-0.5.0, allure-pytest-2.13.2, asyncio-0.23.6, selenium-4.1.0, xdist-3.5.0, variables-3.1.0, rerunfailures-13.0, html-4.1.1, progress-1.2.5, metadata-3.0.0, twisted-1.14.1, picked-0.5.0, anyio-4.3.0, Faker-24.0.0, trio-0.8.0, repeat-0.9.3, base-url-2.1.0, dependency-0.6.0, dotenv-0.5.2, timeout-2.2.0
asyncio: mode=Mode.STRICT
collecting ... Custom conftest.py loaded successfully
collected 1 item                                                                                                                                                                                                                                        

tests/test_example.py::test_env_variable PASSED

=================================================================================================================== 1 passed in 0.04s ===================================================================================================================
root@Gavin:~/test/hook#

小结

通过自定义pytest_load_initial_conftests钩子函数,我们可以在测试运行之前进行各种初始化操作,如修改conftest.py文件路径、设置环境变量等。这将有助于你更灵活且有针对性地配置和运行测试环境,满足不同的项目需求。


文章作者: Gavin Wang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Gavin Wang !
  目录