我使用easy_install在Mac上安装pytest,并开始为文件结构像这样的项目编写测试:

repo/
repo/app.py
repo/settings.py
repo/models.py
repo/tests/
repo/tests/test_app.py


运行py.test而在repo目录中,一切正常就像您期望的那样,但是当我在linux或Windows上尝试相同的东西时(两者都具有pytest 2.2.3),只要它第一次从我的应用程序路径中导入某些东西,它就会发出吠声。例如说from app import some_def_in_app

我是否需要编辑PATH才能在这些系统上运行py.test?有人经历过吗?

评论

这是使用setuptools修复它的方法。

请检查@hoefling答案,并考虑更改您接受的答案,如果SO允许的时间很长的话,那就更好了!

#1 楼

是的,如果您将cd转到tests目录,则源文件夹不在Python的路径中。

您有2种选择:



将路径手动添加到测试文件中,如下所示:

import sys, os
myPath = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, myPath + '/../')


使用env var PYTHONPATH=../运行测试。


评论


我什么时候到目录?我正在从根目录运行py.test。除非我弄错了,而且你的意思是pytest遍历我的文件夹

–马托·托德(MattoTodd)
2012年4月20日在21:46

如果是cd问题,我也不会在Mac上打吗?

–马托·托德(MattoTodd)
2012年4月20日在21:46

哦,我误读了,并认为它在tests目录中不起作用。建议1中的技巧仍然有效。我只使用Linux,所以无法解释其他操作系统上的行为。

–Not_a_Golfer
2012年4月20日在21:50

您所有的test.py文件上都有类似的导入内容吗?

–马托·托德(MattoTodd)
2012年4月20日在21:50

是的,但是我的目录结构通常略有不同-我通常将/ src和/ test保留在根目录下。

–Not_a_Golfer
2012年4月20日在21:51

#2 楼

我不确定为什么py.test不会在PYTHONPATH本身中添加当前目录,但是这是一种解决方法(将从存储库的根目录执行):

python -m pytest tests/


之所以有效,是因为Python为您添加了当前目录在PYTHONPATH中。

评论


如果您具有用于运行应用程序的代码,而不是在执行命令的级别上,则需要将相对导入重写为绝对导入。例如:project / test / all-my-tests和project / src / app.py,由于这一更改,需要使用project / src中的__main__.py文件间接调用app.py,这样才能使用调用python -m src。据我所知,这很混乱。

–塞尔菲·卡尔斯塔尔(Zelphir Kaltstahl)
16-09-26在15:44

@Zelphir:建议使用绝对导入。 Habnabit's有一篇有关打包最佳实践的好文章:blog.habnab.it/blog/2013/07/21/python-packages-and-you,PEP8说:“切勿使用隐式相对导入,并且应在Python中将其删除3.”请参阅:python.org/dev/peps/pep-0008。

– Apteryx
16-11-04在20:23



@Apteryx您的意思是“绝对项目”对吗?因为像/ home / user / dev / projectxyz / src ...这样的东西真的很糟糕,在大多数情况下不能在其他计算机上运行。我想我的意思是,即使模块与文件运行在同一文件夹中,我也必须始终将整个项目根目录写入模块路径。我不知道这是最佳做法,因此,这是有用的信息,谢谢。我仍然同意pep8的大部分内容,尽管它仍然不完美。

–塞尔菲·卡尔斯塔尔(Zelphir Kaltstahl)
16年11月6日在19:44

@Zelphir,是的,这就是我的意思。我相信Python中的绝对导入一词总是指“绝对项目”。请参阅:python.org/dev/peps/pep-0328/#rationale-for-absolute-imports。实际上,我敢肯定,至少从默认的“导入”机制出发,您不能从随机的绝对路径位置导入。

– Apteryx
16年11月7日在18:37

我在测试中添加了__init__.py,从而解决了该问题。现在我可以使用pytest

– Kiran Kumar Kotari
18/12/26在6:08

#3 楼


conftest解决方案

侵入性最小的解决方案是在conftest.py目录中添加一个名为repo/的空文件:

$ touch repo/conftest.py


就是这样。无需编写自定义代码来处理sys.path或记住将PYTHONPATH拖在一起,或将__init__.py放到不属于它的目录中。

之后的项目目录:

repo
├── conftest.py
├── app.py
├── settings.py
├── models.py
└── tests
     └── test_app.py


说明

pytest在测试集合中查找conftest模块以收集自定义钩子和固定装置,并为了从中导入自定义对象,pytest添加了父目录conftest.pysys.path(在本例中为repo目录)中。

其他项目结构

如果您具有其他项目结构,请将conftest.py放在程序包的根目录(一个包含软件包但本身不是软件包的软件包,因此不包含__init__.py),例如:

repo
├── conftest.py
├── spam
│   ├── __init__.py
│   ├── bacon.py
│   └── egg.py
├── eggs
│   ├── __init__.py
│   └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py



src布局

尽管此方法可以与src布局一起使用(将conftest.py放置在src目录中):

repo
├── src
│   ├── conftest.py
│   ├── spam
│   │   ├── __init__.py
│   │   ├── bacon.py
│   │   └── egg.py
│   └── eggs 
│       ├── __init__.py
│       └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py


请注意,添加srcPYTHONPATH减轻了src布局的含义和好处!您将最终从存储库而不是已安装的软件包中测试代码。如果您需要这样做,也许根本不需要src目录。

哪里可以去这里

当然,conftest模块不仅仅是一些文件帮助发现源代码;这是pytest框架的所有特定于项目的增强功能以​​及测试套件的自定义的地方。 pytest有关conftest模块的很多信息,这些信息分散在他们的文档中;以conftest.py开头:本地按目录插件

SO还对conftest模块有一个很好的问题:在py.test中,conftest.py文件的用途是什么?

评论


@ aaa90210尽管我无法重现您的问题(从根目录中的conftest进行导入可以在任何级别上进行),但是您绝对不应从conftest文件中进行导入,因为它是pytest的保留名称,强烈建议您不要这样做。这样,您就可以为将来的错误种植种子。创建另一个名为utils.py的模块,并将代码放置在此处以便在测试中重用。

– hoe
19年1月15日在22:09

竖起大拇指!这是唯一对我有效的解决方案。

– 130nrd
19年5月23日在5:58

应该绝对是公认的答案-谢谢!

–马丁·佩克(Martin Peck)
19年7月30日在20:48

从逻辑上讲,conftest.py不属于应用程序代码,并且imo将其放在src /下是不正确的。

–尼克·奥莱(Nik O'Lai)
4月27日14:01

这个答案应该是SO上的固定标头。非常感谢。

– Rigoberta Raviolini
5月1日8:00

#4 楼

我有同样的问题。我通过在我的__init__.py目录中添加一个空的tests文件来修复它。

评论


请注意,py.test不建议这样做:避免在测试目录中使用“ __init__.py”文件。这样,您可以针对已安装的mypkg版本轻松进行测试,而与安装的软件包是否包含测试无关。 SRC:pytest.org/latest/goodpractises.html

– K.-Michael Aye
2014年5月30日21:52



我来这里遇到同样的问题,发现从测试目录中删除__init__.py对我来说解决了。

–́101
15-10-13在0:24



@mafro我没看到问题吗?测试不必是可导入的代码,它们由测试运行程序发现。只有要测试的代码应该是已安装的软件包/模块,而不是测试。

– K.-Michael Aye
15年11月3日,19:01

在test /的子目录中添加__init__.py可以绝对导入,以针对要安装的模块在该子目录中运行特定的测试。谢谢。

–布莱斯·昆塔(Bryce Guinta)
16年9月9日在22:01

你去了那里:doc.pytest.org/en/latest/goodpractices.html真的很容易用google找到。

– K.-Michael Aye
17年1月12日,0:56

#5 楼

使用以下模块将pytest本身作为模块运行:
python -m pytest tests

评论


这似乎是一个可行的解决方案,但是有人可以解释为什么吗?我宁愿解决根本原因,而不是只使用python -m pytest而不作任何其他解释,而不是“因为它起作用”

–珍妮·恩伯格
18年8月23日在8:30

例如,当项目层次结构为:package / src package / tests以及从src导入的测试时,就会发生这种情况。作为模块执行时,会将导入视为相对于执行位置而言是绝对导入。

–斯特凡诺·墨西拿(Stefano Messina)
18年8月23日在11:55



这个解决方案对我有帮助,谢谢!原因是由于Python版本中的冲突。 pytest测试适用于早期的python版本。在我的情况下,我的python版本是3.7.1,python -m pytest测试有效,但pytest测试无效。

–张如曦
19年1月4日在19:16

来自Pytest:“使用python -m pytest [...]而不是pytest运行pytest会产生几乎相同的行为,除了前一个调用会将当前目录添加到sys.path。”

–摩纳哥(Moad Ennagi)
19年9月4日在14:55

#6 楼

您可以在项目根目录中使用PYTHONPATH运行

PYTHONPATH=. py.test


,或使用pip install作为可编辑导入

pip install -e .   # install package using setup.py in editable mode


评论


对于不在src目录结构中的测试目录并从同时包含test和src目录的目录进行调用,这对我不起作用。

–塞尔菲·卡尔斯塔尔(Zelphir Kaltstahl)
16年3月13日在22:53

#7 楼

我创建此文件是为了回答您的问题和我自己的困惑。希望对您有所帮助。请注意py.test命令行和tox.ini中的PYTHONPATH。

https://github.com/jeffmacdonald/pytest_test

特别是:告诉py.test和tox在哪里找到要包含的模块。

使用py.test可以执行以下操作:

PYTHONPATH=. py.test


并使用tox将其添加到tox.ini中:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}


评论


您能为您链接的项目做一个简短的解释吗?

– J法比安·迈耶(J Fabian Meier)
16年7月15日在14:06

也许只是我一个人,但是该项目上的自述文件非常详细,我对stackoverflow的评论说明了为什么创建回购协议。

–杰夫·麦克唐纳(Jeff MacDonald)
16年7月15日在14:10

尽管这不是严格必要的,但通常的策略是将答案的主要内容包含在答案本身中,因为这样可以确保从现在起x年内(当链接的资源可能已久逝时)该答案是可以理解的。

– J法比安·迈耶(J Fabian Meier)
16年7月15日在14:13

:) 那好吧。多数民众赞成在互联网上。

–杰夫·麦克唐纳(Jeff MacDonald)
16年7月15日在14:41

#8 楼

我在Flask中遇到了同样的问题。

当我添加以下内容时:

__init__.py


到测试文件夹中,问题消失了:)

应用程序可能无法将文件夹测试识别为模块

评论


感谢您的回答。这是解决这个问题的最简单方法

– bwangel
11月8日,3:21

#9 楼

当我不小心将ConftestImportFailure: ImportError('No module named ...文件添加到我的src目录中时,我开始收到奇怪的__init__.py错误(这不应该是Python包,而只是所有来源的容器)。

#10 楼

我通过删除源代码的父文件夹中的顶级__init__.py来修复它。

评论


为我修复。有人可以解释吗?

–更高
19年8月14日在20:40

这里的权利也为我解决了。如果有人有的话,我一定很乐意看到对此的解释

– king_wayne
19年11月7日在21:20

我添加了init.py,但仍然遇到相同的问题,但是此解决方案也对我有用。

–阿比吉特
19年11月18日在12:41

#11 楼

在遵循Flask教程时,我遇到了同样的问题,我在Pytest官方文档中找到了答案。
与我(以及我认为还有很多其他人)用于做事的方式有些不同。

您必须在项目的根目录中至少使用以下两行创建一个setup.py文件:

from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())


其中PACKAGENAME是您应用的名称。然后,您必须使用pip安装它:

pip install -e .


-e标志告诉pip以可编辑或“开发”模式安装软件包。因此,下次运行pytest时,它将在标准PYTHONPATH中找到您的应用。

#12 楼

我有一个类似的问题。 pytest无法识别我正在工作的环境中安装的模块。

我也通过将pytest安装到同一环境中来解决了该问题。

评论


尽管我是从venv内部使用pytest的,但我也在全局安装了它,这给了我这个错误。卸载全局版本并在venv内安装后,它可以正常工作。

– Markus Ressel
3月10日3:41

#13 楼

由于出现了一些更简单的事情(您甚至可以说微不足道),我遇到了此错误。我尚未安装pytest模块。因此,一个简单的apt install python-pytest为我修复了它。

'pytest'将作为测试依赖项在setup.py中列出。确保同时安装测试要求。

#14 楼

对我而言,问题是Django连同tests.py目录生成的tests。删除tests.py解决了该问题。

#15 楼

我错误地使用了相对导入,因此出现了此错误。在OP示例中,test_app.py应该使用例如

from repo.app import *


导入函数,但是__init__.py文件在文件结构中散乱地散布了,这不起作用并创建了除非文件和测试文件位于同一目录中,否则会看到类似ImportError的错误。

from app import *


下面是我与一个项目有关的示例:

这是我的项目结构:

microbit/
microbit/activity_indicator/activity_indicator.py
microbit/tests/test_activity_indicator.py


为了能够从test_activity_indicator.py访问activity_indicator.py,我需要:


以正确的相对导入启动test_activity_indicatory.py:

    from microbit.activity_indicator.activity_indicator import *



在整个项目结构中放入__init__.py文件:

    microbit/
    microbit/__init__.py
    microbit/activity_indicator/__init__.py
    microbit/activity_indicator/activity_indicator.py
    microbit/tests/__init__.py
    microbit/tests/test_activity_indicator.py


#16 楼

根据Dirk Avery在Medium上发表的一篇文章(并得到我的个人经验的支持),如果您在项目中使用虚拟环境,则无法在系统范围内安装pytest;您必须将其安装在虚拟环境中并使用该安装。

特别地,如果您在两个地方都安装了它,则仅运行pytest命令将不起作用,因为它将使用系统安装程序。正如其他答案所述,一个简单的解决方案是运行python -m pytest而不是pytest;之所以有效,是因为它使用了环境版本的pytest。另外,您也可以卸载系统的pytest版本;重新激活虚拟环境后,pytest命令应该可以使用。

评论


到目前为止,对我唯一有用的是python -m pytest tests /。

–尼克·奥莱(Nik O'Lai)
4月27日14:10

#17 楼

正如Luiz Lezcano Arialdi所指出的那样,正确的解决方案是将您的程序包安装为可编辑的程序包。
由于我使用的是pipenv,所以我考虑逐步将如何安装当前路径添加到他的回答中作为可与Pipenv一起使用的东西,它允许运行pytest而不需要任何混乱的代码或宽松的文件。
您将需要具有以下最小的文件夹结构(文档):
package/
    package/
        __init__.py
        module.py
    tests/
        module_test.py
    setup.py

设置。 py的大多数代码如下(文档):
import setuptools


setuptools.setup(name='package', # Change to your package name
                 packages=setuptools.find_packages())

然后您只需要运行pipenv install --dev -e .,pipenv会将当前路径安装为可编辑包(--dev标志是可选的)(文档) 。
现在您应该可以毫无问题地运行pytest

#18 楼

我们通过添加以下环境变量解决了该问题。
PYTHONPATH=${PYTHONPATH}:${PWD}/src:${PWD}/test


#19 楼

另外,如果您在虚拟环境中运行pytest,请确保在虚拟环境中安装了pytest模块。激活您的虚拟环境并运行pip install pytest

#20 楼

很多时候,由于无法导入模块而导致测试中断。经过研究,我发现系统在错误的位置查看文件,我们可以通过复制包含模块的文件轻松地解决该问题。与所述文件夹相同,以便正确导入。另一个解决方案建议是更改导入的声明,并向MutPy显示单元的正确路径。但是,由于多个单元可以具有此依赖性,这意味着我们还需要在其声明中提交更改,因此,我们希望将单元简单地移动到文件夹中。

评论


还提供了OP的问题的其他答案,这些答案已在一段时间前发布。发布答案时,请确保添加新的解决方案或实质上更好的解释,尤其是在回答较旧的问题时。有时最好在特定答案上发表评论。

–help-info.de
19-10-5在17:16

除了来自@ help-info.de的评论外:这是回答问题的指南的链接:stackoverflow.com/help/how-to-answer

– NOD之手
19-10-5在17:30

#21 楼

我的解决方案:

conftest.py目录中创建test文件,其中包含:

import os
import sys
sys.path.insert(0,os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/code/")


这会将感兴趣的文件夹添加到python路径中,而无需修改每个测试文件,设置环境变量或弄乱绝对/相对路径。