将 pytest 与 src 层一起使用

问题描述 投票:0回答:4

pytest 建议包含一个额外的目录来分隔项目中的源代码:

my_package
├── src  # <-- no __init__.py on this layer
│   └── my_package
│       ├── __init__.py
│       └── util_module
│           ├── __init__.py
│           └── utils.py
└── tests
    ├── __init__.py
    └── test_util_module
        ├── __init__.py
        └── test_utils.py

可悲的是,他们没有提到[1]关于测试代码中的导入在这种情况下应该如何工作,这对于我的IDE在这个简单的示例[2]中工作得很好,但会导致以下错误: py测试:

~/my_package$ pytest

====================== test session starts ======================
platform linux -- Python 3.6.4, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/user/workspace/my_package, inifile:
collected 0 items / 1 errors     
                                                                                                                                                                      
============================ ERRORS =============================
___ ERROR collecting tests/test_util_module/test_utils.py ___
ImportError while importing test module '/home/user/workspace/my_package/tests/test_util_module/test_utils.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_util_module/test_utils.py:1: in <module>
    from test.test_module.some_file import starify
E   ModuleNotFoundError: No module named 'my_package.util_module'
!!!! Interrupted: 1 errors during collection !!!!!

我可以通过将测试的导入更改为

来解决该问题
from src.my_package.util_module.utils import starify

但是我的 IDE 抱怨

src
部分是多余的,所以我想将其保留。


[1]:不再是这样了。从版本 3.7.3 开始,pytest 建议使用可编辑安装,这也出现在 @hoefling 的答案中,位于其良好实践顶部。

[2]:设置为

virtualenv env -p python3.6; source env/bin/activate; pip install pytest

python pytest python-packaging
4个回答
133
投票

pytest>=7
的推荐方法:使用
pythonpath
设置

最近,

pytest
添加了一个新的核心插件,支持通过
sys.path配置值
进行
pythonpath
修改。因此,现在解决方案更加简单,不再需要任何解决方法:

pyproject.toml
示例:

[tool.pytest.ini_options]
pythonpath = [
  "src"
]

pytest.ini
示例:

[pytest]
pythonpath = src

路径条目是相对于根目录计算的,因此在这种情况下,

src
条目将
path/to/project/src
目录添加到
sys.path

还允许多个路径条目:对于布局

repo/
├── src/
|   └── lib.py
├── src2/
|   └── lib2.py
└── tests
    └── test_lib.py

配置

[tool.pytest.ini_options]
pythonpath = [
  "src", "src2",
]

[pytest]
pythonpath = src src2

会将

lib
lib2
模块添加到
sys.path
,所以

import lib
import lib2

两者都可以工作。

原答案

调整

PYTHONPATH
(如评论中的建议)是解决导入问题的一种可能性。另一种是在
conftest.py
目录中添加一个空的
src
文件:

$ touch src/conftest.py

pytest
会将
src
添加到
sys.path
。这是欺骗
pytest
将代码库添加到
sys.path
的简单方法。

但是,当您打算构建发行版时,通常会选择

src
布局,例如提供
setup.py
(在本例中)显式指定根包目录:

from setuptools import find_packages, setup


setup(
    ...
    package_dir={'': 'src'},
    packages=find_packages(where='src'),
    ...
)

并在开发过程中以开发模式安装包(通过

python setup.py develop
pip install --editable .
)。这样,您的包
my_package
就可以正确集成到Python的站点包结构中,无需摆弄
PYTHONPATH


6
投票

从 PyTest 7.0.0 开始,您现在可以使用

pythonpath
选项在
sys.path
中设置一些默认条目。这是最方便的方法。

pytest.ini

[pytest]
pythonpath = src/

pyproject.toml

[tool.pytest.ini_options]
pythonpath = "src/"

如果您使用

tox
,那么您应该在其设置中取消设置,这样您就不会意外测试本地版本,而不是已安装的版本。

tox.ini

[testenv]
commands = pytest ... -o pythonpath=

请参阅文档:https://docs.pytest.org/en/7.1.x/reference/reference.html#confval-pythonpath


3
投票

使用 github 操作时,PYTHONPATH 更新对我不起作用(已知问题)。使用 pytest-pythonpath 安装和 pytest.ini 文件对我有用:

pip install pytest-pythonpath # accompany with python_path in pytest.ini, so PYTHONPATH is updated with location for modules under test

有了这个,基本的“pytest”命令很高兴地找到了子目录中的所有测试,并根据我的 pytest.ini 找到了正在测试的模块(设置为匹配 pycharm 中的源文件夹)


0
投票

演出有点晚了,但我相信可以在

sys.path
中更新
tests/__init__.py
并且它应该可以工作。我相信这就是该插件的作用。

例如。就我而言,目录结构如下所示:

repo/
├── src/
|   └── foo.py
└── tests
    ├── pytest.ini
    ├── conftest.py
    ├── __init__.py  # update sys.path here
    ├── integration
    │   └── ...
    └── unit
        ├── __init__.py
        └── test_foo.py

所以在

__init__.py
我只是这样做:

import sys

sys.path.append("src")

此后

pytest ./tests
就可以工作了。

© www.soinside.com 2019 - 2024. All rights reserved.