我正在尝试设置一个项目(Python 3.4.4、pytest 3.3.1)以使用 pytest,但 pytest 无法在文件或目录中运行测试。我认为我错误地使用了 pytest,但不是正确的工作流程。
我尝试过的
遵循 "Good Integration Practices" 中的建议并且由于个人偏好将源代码和测试放在不同的文件夹中,我按如下方式设置了我的项目:
parent_directory/
setup.py
src/
project_name/
__init__.py # empty
utils.py
tests/
__init__.py # empty
project_name/
__init__.py # empty
test_utils.py # has `import project_name.utils.py`
有了这个精确的设置,"Usage and Invocations"说我应该能够运行测试 使用
python -m pytest
并且 pytest 会将当前目录添加到 sys.path(“除了通过 python 调用也会将当前目录添加到 sys.path。”)。如果我尝试从 parent_directory/src 执行此操作,则不会收集任何测试(收集 0 个项目)。如果我从 parent_directory/ 执行此操作,我会得到 ImportError: No module named 'project_name'。
在 some reading 之后--(参见“测试根路径”),我发现将(空的)conftest.py 添加到 src/“将使 pytest 识别您的未指定 PYTHONPATH 的应用程序模块”。
这样做之后,我可以进入parent_directory/并成功运行
pytest
和
pytest -k test_some_specific_test_function_name
请注意,我可以从 python -m pytest 切换到 pytest,对此我很高兴。
但是,如果我尝试在特定文件(或目录)中运行测试,例如
pytest tests/project_name/test_utils.py
我再次收到 ImportError: No module named 'project_name'。这种行为令我非常惊讶。
我检查过:
- pytest cannot find package when I put tests in a separate directory - 不同的目录结构
- PATH issue with pytest 'ImportError: No module named YadaYadaYada' (第一个建议是
sys.path“hack”,第二个是环境变量,如果一个人同时处理多个项目,这是不切实际的——肯定有更好的方法) - Py.test No module named * - 不同的目录结构
问题
什么是正确的工作流程,可以让我保留我的目录结构,同时最好从 parent_directory/ 调用所有:
pytest
pytest -k test_some_specific_test_function_name
pytest tests/project_name/test_utils.py
没有一些手动 sys.path 黑客攻击。
我确定我遗漏了一些明显的东西。谢谢!
请您参考如下方法:
Pytest 将将当前目录添加到sys.path,但这并不一定意味着它使您的包可以从源代码树中导入。事实上,使用 src 和 test 布局的全部意义在于防止 pytest 针对源代码树进行测试。
您可以通过从项目的顶级目录运行 python 解释器并尝试导入包来自行检查。它不会工作,除非它已经安装在您的工作环境中。
通过使用 src 和 test 布局,pytest 被迫针对已安装的包版本进行测试。参见 this great blog post以这种方式构建项目的动机。这是关键段落:
You will be forced to test the installed code (e.g.: by installing in a virtualenv). This will ensure that the deployed code works (it's packaged correctly) - otherwise your tests will fail. Early. Before you can publish a broken distribution.
所以如果你想在你的项目中使用这种布局,你需要在测试之前安装你的包。这两种方法各有利弊,但 pytest 推荐它,我也倾向于同意。
[更新]
作为方便本地测试的解决方法,您可以在 development mode 中安装您的包使用 setup.py develop 或 pip install -e .。这会使您的包看起来已安装在您的环境中,但源代码树中的任何更新都会立即反射(reflect)在“已安装”版本中。1
如果您选择遵循这种方法,您应该确保您使用的是沙盒开发环境(例如 virtualenv 或 conda),这样您就不会造成污染您的系统环境。
1 您应该知道,如果您的包提供 C/C++ 或 Cython 扩展,则需要手动重建它们。
