确保 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,该文档现在提供了两种方案 - 在应用程序包 inside 或 outside 进行测试,所以我认为这是一个有效的选项?
@AlenSiljak 在实践中,<repo>/tests
仍然受到鼓励,并且不鼓励在代码结构中包含 tests
文件夹。我遇到的 pytest 的一些插件仍然存在不一致的行为(我主要使用覆盖率、isort、flake8)。也就是说,我已经开始将单元测试放在代码库中的 tests
文件夹中,并将集成/系统级别测试放在顶部 运行 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 中包含应用程序目录的主要内容,如果未能解决你的问题,请参考以下文章