在 pytest 项目中,测试文件的放置位置与导入模式的选择直接影响项目的可维护性和隔离性。
关于测试目录布局,pytest 支持两种常见方案:将测试放在应用代码之外(如 tests/),或将测试内联于应用包中。若选择外部目录且采用推荐的可编辑安装(editable install)方式,通常建议配合 src 布局使用。这种结构下,应用源码位于 src/mypkg/,测试文件位于根目录下的 tests/。这样做的好处是:测试既能针对已安装的包运行,也能在本地开发时通过可编辑安装直接运行,且能避免将本地代码误当作已安装包进行测试。
若不使用 src 布局而将测试放在外部目录(如 mypkg/tests/),Python 默认会将当前目录加入 sys.path,使得 pytest 能直接导入本地代码。但这种方式存在隐患:当使用 tox 等工具在虚拟环境中测试时,可能会意外导入本地源码而非已安装的包版本。
若选择内部测试目录(即测试文件位于应用包内部,如 mypkg/tests/),pytest 会将其视为应用包的一部分。此时可使用--pyargs 选项运行测试,pytest 会自动发现已安装或可编辑的包位置并收集测试。但需注意:此模式下必须使用绝对导入来访问应用代码;同时,若目录缺少__init__.py(PEP 420 命名空间包),pytest 仍能正常工作,但内部测试目录仍需遵循目录名与导入名一致的约定。
关于导入模式,pytest 默认使用 prepend 模式,但该模式会修改 sys.path,可能导致模块重复导入或意外导入本地代码。对于新项目,强烈推荐使用 importlib 导入模式(在 pytest.toml 中设置 addopts = ["--import-mode=importlib"])。该模式下,pytest 不会修改 sys.path,测试文件按完整包路径导入(如 tests.foo.test_module),避免了命名冲突和路径污染问题,使行为更直观、可预测。
简言之:新项目推荐采用 src 布局 + 外部测试目录 + importlib 导入模式;若需内联测试,则使用--pyargs 并确保绝对导入与目录结构一致。