通常的 pytest 工作流程 - 无法 运行 在文件中进行测试

Usual pytest workflow - can't run tests in a file

我正在尝试设置一个项目(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 开始执行此操作,则不会收集任何测试 (collected 0 items)。如果我从 parent_directory/ 开始这样做,我会得到 ImportError: No module named 'project_name'

之后——(参见 "Test root path"),我发现添加(一个空的)conftest.pysrc/ " 将让 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'。这种行为让我很惊讶。

我检查过:

问题

什么是正确的工作流程,可以让我保留我的目录结构,同时最好从 parent_directory/ 调用所有:

pytest
pytest -k test_some_specific_test_function_name
pytest tests/project_name/test_utils.py

无需一些手动 sys.path 黑客攻击。

我确定我遗漏了一些明显的东西。谢谢!

Pytest 添加当前目录到 sys.path,但这并不一定意味着它使您的包可以从源代码树中导入。事实上,使用 srctest 布局的全部意义在于 防止 pytest 针对源代码树进行测试。

您可以通过 运行 一个 python 解释器从项目的顶级目录中自行检查并尝试导入包。它不会工作,除非它已经安装在您的工作环境中。

通过使用 srctest 布局,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 推荐它,我倾向于同意。

[更新]

作为方便本地测试的解决方法,您可以使用 setup.py developpip install -e .development mode 中安装您的软件包。这使您的包看起来已安装在您的环境中,但源代码树中的任何更新都会立即反映在 "installed" 版本中。1

如果您选择采用这种方法,您应该确保您使用的是沙盒开发环境(例如 virtualenvconda),以免污染您的系统环境。


1 您应该知道,如果您的软件包提供 C/C++ 或 Cython 扩展,则需要手动重建它们。