将 pytest 与 src 层一起使用

Posted

技术标签:

【中文标题】将 pytest 与 src 层一起使用【英文标题】:Using pytest with a src layer 【发布时间】:2018-10-13 19:01:14 【问题描述】:

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]关于在这种情况下测试代码中的导入应该如何工作,这在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

【问题讨论】:

如果您在运行测试之前导出PYTHONPATH=".:src/",会改变什么吗? 您是否安装了my_package,即它是否包含setup.py @NilsWerner 没有,也没有。在测试之前我应该​​总是这样做吗?我宁愿在构建 CI 之前运行单元测试,但我可能错了。 是的,当然你: 1) 需要构建代码才能对其进行测试。 2)通过安装使包importable "当然你:1) 需要构建代码才能对其进行测试。" - 在一般情况下这是不正确的,对于很多人(包括我自己)来说这是不可取的 【参考方案1】:

调整PYTHONPATH(如 cmets 中所建议的)是解决导入问题的一种可能性。另一个是在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 developpip install --editable .),而您仍在开发它。这样,您的包 my_package 就可以正确集成到 Python 的站点包结构中,而无需摆弄PYTHONPATH

【讨论】:

另外,SO 有一个关于这个主题的excellent answer。 我测试了这两种解决方案并且都有效 =) 感谢您的帮助! 这个官方文档可能会有所帮助:pytest import mechanisms and sys.path/PYTHONPATH【参考方案2】:

使用 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中的源文件夹)

【讨论】:

以上是关于将 pytest 与 src 层一起使用的主要内容,如果未能解决你的问题,请参考以下文章

将pytest与xdist一起使用时如何打印输出

如何将 pytest 与 virtualenv 一起使用?

pytest接口自动化测试框架 | 汇总

pytest完整

pytest之标记mark

基于fixture的自动pytest.mark装饰