解决 pytest 的 conftest.py 文件过大问题。
1. 项目目录结构
project_name
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── project_name
│ ├── __init__.py
│ ├── testing
│ │ ├── __init__.py
│ │ ├── fixture.py
├── tests
│ ├── __init__.py
│ ├── conftest.py
│ ├── fixtures
│ │ ├── __init__.py
│ │ ├── cache.py
│ │ ├── loop.py
│ │ ├── net.py
│ │ ├── request.py
│ │ ├── signal.py
│ │ └── thread.py
2. 使用 pytest_plugins
加载 fixture
在 conftest.py
中添加 pytest_plugins
配置,使用 append_pytest_fixture_plugins
方法加载 fixtures
目录中的 fixture
,fixtures
目录下的子目录也会一起加载。
from pathlib import Pathfrom project_name.testing.fixture import append_pytest_fixture_pluginspath = Path(__file__).parent / "fixtures"
root_path = Path(__file__).parent.parent
pytest_plugins = append_pytest_fixture_plugins(root_path, path)
通过这种方式,可以将 conftest.py
中的 fixtures
拆分到多个文件中,方便维护和管理。拆分的文件如下,
│ ├── fixtures
│ │ ├── __init__.py
│ │ ├── cache.py
│ │ ├── loop.py
│ │ ├── net.py
│ │ ├── request.py
│ │ ├── signal.py
│ │ └── thread.py
3. append_pytest_fixture_plugins
函数实现
from pathlib import Path
from typing import Listimport pytestdef append_pytest_fixture_plugins(root_path: Path, path: Path) -> List[str]:"""添加额外的 fixtures"""def refactor(_path: str) -> str:return _path.strip("/").strip("\\").replace("/", ".").replace("\\", ".").replace(".py", "")paths = []prefix = str(root_path)prefix_len = len(prefix)# 递归遍历目录下所有文件for path in path.iterdir():if not path.is_file():continuefilename = path.name# 去掉 __init_.pyif filename.startswith("__"):continue# 过滤掉非 python 文件if filename.endswith(".py"):paths.append(refactor(str(path)[prefix_len:]))return paths
单元测试如下
from pathlib import Pathfrom project_name.testing.fixture import append_pytest_fixture_pluginsdef test_append_pytest_fixture_plugins():path = Path(__file__).parent / "fixtures"root_path = Path(__file__).parent.parentactual = append_pytest_fixture_plugins(root_path, path)expect = ["tests.fixtures.thread","tests.fixtures.signal","tests.fixtures.net","tests.fixtures.request","tests.fixtures.cache","tests.fixtures.loop",]assert actual == expect