如何避免uv构建的Python包包含同文件内的测试函数?
如何在Python源码文件中内嵌单元测试且不导出测试函数(类似Rust #[cfg(test)])
我用uv和pyproject.toml管理Python包,希望像Rust的#[cfg(test)]那样,把单元测试和源码放在同一文件,tests/目录仅用于集成测试。目前在源码里直接写的测试函数会和业务函数一起被导出,示例代码如下:
# add.py def add(a, b): return a + b def test_add(): assert add(1, 2) == 3
用uv run pytest能正常执行测试,但构建包后test_add会被模块导出,想解决这个问题。自己尝试过通过检查sys.modules是否包含"pytest"来条件定义测试函数,但觉得这种方式不够稳妥。
可靠的解决方案
方案1:基于sys.modules的条件判断(优化版)
你的思路本质是可行的,只需稍作优化就能提升可靠性。pytest运行时会提前加载自身模块,因此sys.modules中必然存在"pytest";而正常运行或构建包时,该模块不会被加载,测试函数也就不会被定义:
# add.py import sys def add(a, b): return a + b # 仅在pytest运行环境下定义测试函数 if "pytest" in sys.modules: def test_add(): assert add(1, 2) == 3
如果担心极端场景下的误判,可以结合命令行参数检查进一步增强严谨性:
import sys def add(a, b): return a + b # 同时检查pytest模块是否加载、命令行是否包含pytest相关参数 if "pytest" in sys.modules or any("pytest" in arg for arg in sys.argv): def test_add(): assert add(1, 2) == 3
方案2:使用__test__字典隐藏测试函数
将测试函数定义为私有函数,再通过模块的__test__字典注册给pytest。这样测试函数不会成为模块的顶级导出成员,但pytest仍能正常识别并执行:
# add.py def add(a, b): return a + b # 用于注册测试用例的字典,pytest会自动识别 __test__ = {} # 私有测试函数,不会被模块导出 def _test_add(): assert add(1, 2) == 3 # 将私有测试函数注册到__test__字典 __test__["test_add"] = _test_add
验证效果
用uv build构建包后,安装并导入模块:
from foo import add # 尝试访问test_add会抛出AttributeError print(dir(add)) # 输出中不会包含test_add或_test_add
同时uv run pytest仍能正常发现并执行测试用例。
内容的提问来源于stack exchange,提问作者FISR
相关产品推荐
相关产品推荐

