pytest项目:自定义目录收集器使用指南
2025-07-06 03:43:30作者:柏廷章Berta
理解pytest默认目录收集机制
pytest框架在测试收集阶段会自动扫描项目目录结构,默认情况下会使用两种收集器处理不同类型的目录:
- 对于包含
__init__.py
文件的目录,使用pytest.Package
收集器 - 对于普通目录,使用
pytest.Dir
收集器
这种默认行为适用于大多数场景,但当我们需要更精细地控制测试收集过程时,就需要自定义目录收集器。
为什么需要自定义目录收集器
在实际项目中,我们可能会遇到以下需求:
- 需要基于特定文件(如manifest文件)控制测试收集
- 希望实现动态测试收集逻辑
- 需要对不同目录应用不同的收集策略
- 需要过滤或转换收集到的测试项
这些需求都可以通过实现自定义目录收集器来满足。
实现自定义目录收集器
核心组件
- 自定义Directory类:继承自
pytest.Directory
,实现特定收集逻辑 - pytest_collect_directory钩子:用于注册自定义收集器
示例:基于manifest.json的收集器
下面我们通过一个完整示例来演示如何实现基于manifest文件的目录收集器。
1. 创建conftest.py
import json
import pathlib
import pytest
class ManifestDirectory(pytest.Directory):
def collect(self):
manifest_path = self.path / "manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text())
for file_pattern in manifest.get("files", []):
for path in self.path.glob(file_pattern):
if path.name.endswith(".py") and path.is_file():
yield pytest.Module.from_parent(self, path=path)
else:
yield from super().collect()
def pytest_collect_directory(path, parent):
if (path / "manifest.json").exists():
return ManifestDirectory.from_parent(parent, path=path)
return None
2. 创建manifest.json
{
"files": [
"test_first.py",
"test_second.py"
]
}
3. 创建测试文件
# test_first.py
def test_1():
assert True
# test_second.py
def test_2():
assert True
# test_third.py
def test_3():
assert True
工作原理分析
-
收集过程:
- pytest在收集阶段会调用
pytest_collect_directory
钩子 - 当目录包含manifest.json文件时,返回自定义的ManifestDirectory收集器
- 否则返回None,使用默认收集器
- pytest在收集阶段会调用
-
ManifestDirectory收集器:
- 读取manifest.json文件
- 根据files列表收集指定的测试文件
- 忽略未在manifest中列出的测试文件
执行效果验证
执行测试:
$ pytest
============================ test session starts ============================
collected 2 items
tests/test_first.py . [ 50%]
tests/test_second.py . [100%]
============================ 2 passed in 0.12s =============================
查看收集树:
$ pytest --collect-only
============================ test session starts ============================
collected 2 items
<Dir customdirectory>
<ManifestDirectory tests>
<Module test_first.py>
<Function test_1>
<Module test_second.py>
<Function test_2>
======================== 2 tests collected in 0.12s ========================
高级应用场景
扩展manifest功能
可以进一步扩展manifest.json的功能,例如:
-
测试过滤:
{ "exclude": ["test_*_slow.py"] }
-
标记控制:
{ "markers": { "test_*.py": "smoke" } }
-
参数化配置:
{ "parameters": { "test_api.py": {"base_url": "https://api.example.com"} } }
动态收集策略
可以在收集器中实现更复杂的逻辑:
- 基于环境变量控制收集
- 根据文件内容动态生成测试
- 实现测试依赖关系解析
最佳实践建议
- 保持兼容性:自定义收集器应优雅回退到默认行为
- 明确文档:为团队记录manifest文件的格式和使用方式
- 性能考虑:避免在收集阶段执行耗时操作
- 错误处理:妥善处理manifest文件解析错误
总结
通过自定义目录收集器,我们可以实现高度灵活的测试收集策略,满足各种复杂项目的需求。本文展示的manifest文件方案只是一个起点,开发者可以根据实际需求扩展出更强大的收集逻辑。
掌握这项技术后,你将能够:
- 精确控制测试收集范围
- 实现基于配置的测试过滤
- 为不同目录应用不同的测试策略
- 构建更智能的测试基础设施