import terror:没有名为yadayadayada的模块;

我使用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。测试这些系统?有人经历过吗?

308780 次浏览

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

你有两个选择:

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

    import sys, os
    myPath = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, myPath + '/../')
    
  2. Run the tests with the env var PYTHONPATH=../.

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

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

PYTHONPATH=. py.test

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

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

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

python -m pytest tests/

它能工作是因为Python为你在PYTHONPATH中添加了当前目录。

我创建这个是为了回答你的问题和我自己的困惑。我希望这能有所帮助。注意py. conf文件中的PYTHONPATH。测试命令行和tox.ini。

https://github.com/jeffmacdonald/pytest_test

具体来说:您必须告诉py。测试和毒害在哪里找到您包含的模块。

py。测试你可以这样做:

PYTHONPATH=. py.test

使用tox,将这个添加到你的tox.ini:

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

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

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

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

pytest本身作为一个模块运行: python -m pytest tests < / p >

pytest>=7的推荐方法:使用pythonpath设置

最近,pytest添加了一个新的核心插件,支持通过pythonpath配置值. c修改sys.path。因此,现在的解决方案要简单得多,不再需要任何变通:

pyproject.toml例子:

[tool.pytest.ini_options]
pythonpath = [
"."
]

pytest.ini例子:

[pytest]
pythonpath = .

路径条目是相对于rootdir计算的,因此在本例中,.repo目录添加到sys.path

多个路径条目也被允许:对于一个布局

repo/
├── src/
|   └── lib.py
├── app.py
└── tests
├── test_app.py
└── test_lib.py

配置

[tool.pytest.ini_options]
pythonpath = [
".", "src",
]

[pytest]
pythonpath = . src

将同时添加applib模块到sys.path,那么

import app
import lib

都可以。

原始答案(不建议用于最新的pytest版本;仅用于pytest<7): conftest解决方案

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

$ touch repo/conftest.py

就是这样。不需要编写自定义代码来破坏sys.path或记住拖拽PYTHONPATH,或将__init__.py放入不属于它的dirs中(尽管在几维回答中建议使用python -m pytest是一个很好的解决方案!)。

之后的项目目录:

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

解释

pytest在测试集合上查找conftest模块来收集自定义钩子和fixture,为了从它们导入自定义对象,__ABC0将__ABC3的父目录添加到sys.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

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

从这里往哪里走

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

另外,SO有一个关于conftest模块的很好的问题:py。测试,conftest。py文件有什么用? . c

对我来说,问题是Django生成的tests.pytests目录。删除tests.py解决了这个问题。

我得到这个错误,因为我使用相对导入不正确。在OP示例中,test_app.py应该使用e.g.导入函数。

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_indicator .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

我也遇到过类似的问题。pytest无法识别安装在我工作的环境中的模块。

我通过在相同的环境中安装pytest来解决这个问题。

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

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

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

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

我在遵循Flask教程时遇到了同样的问题,我在官方Pytest docs上找到了答案 这与我(以及我认为许多人)过去做事的方式有一点不同

你必须在项目的根目录中创建一个setup.py文件,至少包含以下两行:

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

其中PACKAGENAME是应用程序的名称。然后你要用pip安装它:

pip install -e .

-e标志告诉pip以可编辑或“开发”模式安装包。所以下次你运行pytest时,它应该在标准的PYTHONPATH中找到你的应用程序。

我在弗拉斯克也遇到了同样的问题。

当我补充说:

__init__.py

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

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

我的解决方案:

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

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

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

正如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了。

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

PYTHONPATH=${PYTHONPATH}:${PWD}/src:${PWD}/test

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

有点遗憾,这在python中是一个问题…但在我看来,加入这个环境变量是最舒服的方式:

export PYTHONPATH=$PYTHONPATH:.

把这个放进你的。zshrc/。bashrc。

由于没有人建议这样做,你也可以在pytest.ini文件中传递测试的路径:

[pytest]
...
testpaths = repo/tests

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

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

如果这个pytest错误不是出现在您自己的包上,而是出现在包的requirements.txt中的git安装包上,解决方案是切换到可编辑的安装模式。

例如,假设你的包的requirements.txt有如下一行:

git+https://github.com/foo/bar.git

您可以将其替换为以下内容:

-e git+https://github.com/foo/bar.git#egg=bar