确保 py.test 在 sys.path 中包含应用程序目录

Posted

技术标签:

【中文标题】确保 py.test 在 sys.path 中包含应用程序目录【英文标题】:Ensuring py.test includes the application directory in sys.path 【发布时间】:2014-01-25 03:14:25 【问题描述】:

我有一个项目目录结构如下(我认为这很标准):

my_project
    setup.py
    mypkg
        __init__.py
        foo.py
    tests
        functional
            test_f1.py
        unit
            test_u1.py

我正在使用 py.test 作为我的测试框架,并且我希望能够在 my_project 目录中运行 py.test tests 来运行我的测试。这确实有效,直到我尝试在测试中使用(例如)import mypkg 导入我的应用程序代码。那时,我收到错误“没有名为 mypkg 的模块”。经过一番调查,似乎py.test 使用sys.path 中的测试文件目录运行测试,但不是运行py.test 的目录。

为了解决这个问题,我在我的tests 目录中添加了一个conftest.py 文件,其中包含以下代码:

import sys, os

# Make sure that the application source directory (this directory's parent) is
# on sys.path.

here = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, here)

这似乎可行,但它是确保测试看到应用程序代码的好方法吗?有没有更好的方法来实现这一点,还是我在项目结构上做错了什么?

我查看了一些使用py.test(例如pip)的其他项目,但我看不到执行此类操作的代码,但运行py.test tests 似乎在那里工作。我不知道为什么,但我担心他们可能会以更简单的方式获得相同的结果。

我查看了py.test 文档,但我看不到对此问题的解释或推荐的解决方法。

【问题讨论】:

【参考方案1】:

正如您所说,py.test 基本上假定您已正确设置 PYTHONPATH。有几种方法可以实现:

给你的项目一个 setup.py 并在这个项目的 virtualenv 中使用pip install -e .。这可能是标准方法。

如果你有一个 virtualenv 但没有 setup.py,作为一个变体,使用你的 venv 工具在 sys.path 上添加项目目录,例如pew add . 如果你使用 pew,或者add2virtualenv . 如果你使用 virtualenv 和 virtualenvwrapper 的扩展。

如果您总是喜欢 sys.path 上的当前工作目录,您可以随时在 shell 中导出 PYTHONPATH=''。这是确保 sys.path 上的空字符串,python 将其解释为当前工作目录。不过,这可能存在安全隐患。

我自己最喜欢的 hack,滥用 py.test 加载 conftest 文件的方式:在项目的***目录中放置一个空的 conftest.py

py.test 以这种方式运行的原因是为了便于在结帐的 tests/ 目录中针对已安装的包运行测试。如果它会无条件地将项目目录添加到 PYTHONPATH,那么这将不再可能。

【讨论】:

只是补充一点:如果你没有virtualenv,你可以使用“python setup.py develop”达到同样的效果。 conftest.py hack 是个好主意!!!太糟糕了,这是一种滥用,IOW它可能会消失:( 安装一些东西来运行测试???使用更多工具只是为了让测试运行器工作???操纵 Python 路径,这是不推荐的,并且每当在项目中移动某些东西时都必须再次更改??? - 不!添加一个空文件似乎是最简单的解决方案!我不知道它为什么起作用,但我很高兴它起作用了。其他选项似乎是错误的,直到有人向我解释为什么我需要安装一些东西来测试它,当我已经准备好所有代码时。 @PascalVKooten 最近在here 上讨论了为什么这个conftest.py 黑客“有效”,以及为什么pytest 没有“撤消”这个sys.path 修改后正在导入。 @Zelphir 至于为什么要先安装一些东西来测试它,好吧,您可以将其视为同时测试 installer 本身的一种方式。如果没有这一步,完全有可能有一个通过的测试套件,但安装程序损坏(您最终会意外发布损坏的包)。【参考方案2】:

这样做的简单方法是,在终端/cmd 中将目录更改为父目录所在的位置(例如,在本例中为 cd C:/.../my_project)。

然后运行: python -m pytest --cov=mypkg tests

无需弄乱PYTHONPATH 环境变量。 通过python -m pytest运行,它会自动将当前目录添加到sys.path

【讨论】:

+1 这是一个合法且记录在案的功能,而不仅仅是一个意外。见docs.pytest.org/en/latest/…【参考方案3】:

答案实际上要容易得多,如 here 所示。

您需要做的就是将__init__.py 添加到您的测试目录及其每个子目录中,如下所示;

tests/__init__.py
tests/functional/__init__.py
tests/unit/__init__.py

【讨论】:

这实际上将测试添加到包中。这可能并不总是需要的。 –1 因为在"good practices" section of the pytest docs 中明确不鼓励这样做 @BrianBruggeman,我认为 setup.py 中的 packages=find_packages(exclude=['contrib', 'docs', 'tests']) 可以解决这个问题? @wim,该文档现在提供了两种方案 - 在应用程序包 insideoutside 进行测试,所以我认为这是一个有效的选项? @AlenSiljak 在实践中,<repo>/tests 仍然受到鼓励,并且不鼓励在代码结构中包含 tests 文件夹。我遇到的 pytest 的一些插件仍然存在不一致的行为(我主要使用覆盖率、isort、flake8)。也就是说,我已经开始将单元测试放在代码库中的 tests 文件夹中,并将集成/系统级别测试放在顶部 /tests 文件夹中,这对我来说没问题。【参考方案4】:

运行 pytest 引用单个/多个包

1包

PYTHONPATH=$(pwd)/mypkg/ python3 -m pytest 
# or
PYTHONPATH=$(pwd)/mypkg/ python3 -m pytest  path/to/tests

对于 2 个包裹 (pkg1 pkg2)

# Use ; as a separator in windows
PYTHONPATH=/path/to/pkg1/:/path/to/pkg2/ python3 -m pytest tests

【讨论】:

以上是关于确保 py.test 在 sys.path 中包含应用程序目录的主要内容,如果未能解决你的问题,请参考以下文章

确保用户在输入中包含“@”符号[重复]

Python模块

浏览器显示 jpeg 的原始图像数据。我应该确保在响应中包含哪些标题?

python 怎么引用其他文件的类

代码示例: pytest的简单用法

如何确保仅从特定表中选择第一条记录,该表可以在 DB2 中包含多个相同 ID 的记录