313

我使用 easy_install 在 Mac 上安装 pytest 并开始为具有如下文件结构的项目编写测试:

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

在 repo 目录中运行py.test,一切都如你所料

但是当我在 linux 或 windows 上尝试同样的事情时(两者都有 pytest 2.2.3),每当它从我的应用程序路径中第一次导入某些东西时,它就会吠叫。比如说from app import some_def_in_app

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

4

23 回答 23

382

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

python -m pytest tests/

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

于 2015-12-07T18:21:06.537 回答
271

conftest解决方案

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

$ touch repo/conftest.py

就是这样。无需编写自定义代码来修改sys.path或记住拖动PYTHONPATH,或放入__init__.py不属于它的目录中(尽管按照Apteryx答案python -m pytest中的建议使用是一个很好的解决方案!)。

之后的项目目录:

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

请注意,添加srcto 会PYTHONPATH减轻src布局的意义和好处!您最终将测试来自存储库的代码,而不是已安装的包。如果你需要这样做,也许你根本不需要src目录。

从这往哪儿走

当然,conftest模块不仅仅是帮助源代码发现的一些文件;它是框架的所有特定于项目的增强pytest和测试套件的定制发生的地方。pytest有很多关于conftest分散在他们文档中的模块的信息;从conftest.py:本地每个目录插件开始

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

于 2018-05-30T17:42:02.510 回答
135

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

于 2013-09-24T01:20:44.237 回答
125

cd是的,如果您访问测试目录,源文件夹不在 Python 的路径中。

您有 2 个选择:

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

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
    
  2. 使用 env var 运行测试PYTHONPATH=../

于 2012-04-20T21:39:12.060 回答
56

pytest将自身作为一个模块 运行:python -m pytest tests

于 2018-02-02T09:37:03.977 回答
38

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

PYTHONPATH=. py.test

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

pip install -e .   # install package using setup.py in editable mode
于 2014-10-24T09:03:03.420 回答
24

我创建这个是为了回答你的问题和我自己的困惑。我希望它有所帮助。注意 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}
于 2016-07-15T13:46:39.053 回答
24

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

当我添加:

__init__.py

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

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

于 2020-03-10T07:41:03.477 回答
12

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

于 2019-07-03T16:58:17.557 回答
10

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

于 2017-08-14T16:44:07.427 回答
5

我在学习 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

于 2020-03-08T18:34:04.183 回答
3

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

我也通过安装pytest到相同的环境来解决它。

于 2019-04-25T14:12:58.710 回答
3

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

于 2020-12-17T21:22:57.187 回答
2

对我来说,问题是tests.py由 Django 和tests目录一起产生的。删除tests.py解决了问题。

于 2018-12-04T12:10:10.147 回答
2

我收到了这个错误,因为我错误地使用了相对导入。在 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
于 2019-01-16T17:07:24.873 回答
2

这是python中的一个问题有点遗憾......但只需添加这个环境变量是IMO最舒服的方式:

export PYTHONPATH=$PYTHONPATH:.

您可以使用direnv它来自动发生:)

于 2021-07-28T17:00:17.303 回答
1

由于更简单的事情(你甚至可以说微不足道),我得到了这个错误。我没有安装pytest模块。所以一个简单apt install python-pytest的为我解决了它。

'pytest' 将作为测试依赖项列在 setup.py 中。确保您也安装了测试要求。

于 2017-08-28T02:56:21.097 回答
1

由于没有人建议,您还可以将路径传递给pytest.init文件中的测试:

[pytest]
...
testpaths = repo/tests

请参阅文档:https ://docs.pytest.org/en/6.2.x/customize.html#pytest-ini

VScode 的副作用:它应该在 UI 中进行单元测试。

于 2021-11-02T15:09:27.777 回答
0

根据Dirk Avery 在 Medium 上的一篇文章(并得到我个人经验的支持),如果您在项目中使用虚拟环境,那么您不能使用系统范围的 pytest 安装;您必须在虚拟环境中安装它并使用该安装。

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

于 2020-02-29T04:37:39.557 回答
0

正如Luiz Lezcano Arialdi所指出的,正确的解决方案是将您的包安装为可编辑的包。

由于我使用的是 pipenv,我考虑在他的答案中逐步添加如何使用 pipenv 将当前路径安装为可食用的,从而允许运行 pytest 而无需任何修改代码或松散文件。

您将需要具有以下最小文件夹结构(文档):

package/
    package/
        __init__.py
        module.py
    tests/
        module_test.py
    setup.py

setup.py 大多数具有以下最小代码(文档):

import setuptools


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

然后你只需要运行pipenv install --dev -e .,pipenv 就会将当前路径安装为一个可编辑的包(--dev 标志是可选的)(文档)。

现在你应该可以pytest毫无问题地运行了。

于 2020-07-29T23:32:33.087 回答
0

我们通过添加以下环境变量解决了这个问题。

PYTHONPATH=${PYTHONPATH}:${PWD}/src:${PWD}/test
于 2020-09-05T06:53:45.257 回答
-1

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

于 2019-10-05T17:01:30.577 回答
-1

我的解决方案:

在包含以下内容的目录中创建conftest.py文件test

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

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

于 2020-05-21T07:11:47.473 回答