将 pytest 与 src 层一起使用
Using pytest with a src layer
pytest recommends 包括一个额外的目录来分隔项目中的源代码:
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 在 this naive example[2],但会导致pytest出现以下错误:
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 的 good practices.
顶部的回答中。
[2]:设置为 virtualenv env -p python3.6; source env/bin/activate; pip install pytest
针对 pytest>=7
的推荐方法:使用 pythonpath
设置
最近,pytest
添加了一个新的核心插件,支持通过 pythonpath
configuration value 进行 sys.path
修改。因此,现在的解决方案简单多了,不再需要任何解决方法:
pyproject.toml
示例:
[tool.pytest.ini_options]
pythonpath = [
"src"
]
pytest.ini
示例:
[pytest]
pythonpath = src
路径条目是相对于 rootdir 计算的,因此在这种情况下 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
(如评论中所建议)是解决导入问题的一种可能性。另一个是在 src
目录中添加一个空的 conftest.py
文件:
$ 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 的站点包结构中,并且不需要 fiddle 和 PYTHONPATH
。
PYTHONPATH 更新在使用 github 操作时对我不起作用(已知概率)。使用此 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 中的源文件夹)
从 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
pytest recommends 包括一个额外的目录来分隔项目中的源代码:
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 在 this naive example[2],但会导致pytest出现以下错误:
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 的 good practices.
顶部的回答中。[2]:设置为 virtualenv env -p python3.6; source env/bin/activate; pip install pytest
针对 pytest>=7
的推荐方法:使用 pythonpath
设置
最近,pytest
添加了一个新的核心插件,支持通过 pythonpath
configuration value 进行 sys.path
修改。因此,现在的解决方案简单多了,不再需要任何解决方法:
pyproject.toml
示例:
[tool.pytest.ini_options]
pythonpath = [
"src"
]
pytest.ini
示例:
[pytest]
pythonpath = src
路径条目是相对于 rootdir 计算的,因此在这种情况下 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
(如评论中所建议)是解决导入问题的一种可能性。另一个是在 src
目录中添加一个空的 conftest.py
文件:
$ 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 的站点包结构中,并且不需要 fiddle 和 PYTHONPATH
。
PYTHONPATH 更新在使用 github 操作时对我不起作用(已知概率)。使用此 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 中的源文件夹)
从 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