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

Pau*_*ore 42 python unit-testing pytest

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

my_project
    setup.py
    mypkg
        __init__.py
        foo.py
    tests
        functional
            test_f1.py
        unit
            test_u1.py
Run Code Online (Sandbox Code Playgroud)

我正在使用py.test作为我的测试框架,我希望能够py.test testsmy_project目录中运行以运行我的测试.这确实有效,直到我尝试import mypkg在测试中使用(例如)导入我的应用程序代码.那时,我收到错误"没有名为mypkg的模块".在进行一些调查时,似乎py.test运行测试与测试文件的目录sys.path,但不是py.test运行的目录.

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

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)
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但它是确保测试看到应用程序代码的好方法吗?有没有更好的方法来实现这一点,或者我在如何构建项目时做错了什么?

我已经看过其他一些使用的项目py.test(例如,pip但是我看不到代码做了这样的事情,但是运行py.test tests似乎在那里工作.我不知道为什么,但我担心他们可能以更简单的方式取得了同样的结果.

我查看了py.test文档,但是我看不出这个问题的解释或建议的方法来处理它.

flu*_*lub 42

正如你所说,py.test基本上假设你正确设置了PYTHONPATH.有几种方法可以实现这一目标:

  • 为您的项目提供setup.py并pip install -e .在此项目的virtualenv中使用.这可能是标准方法.

  • 如果您有virtualenv但没有setup.py使用您的venv工具在sys.path上添加项目目录,例如,pew add .如果您使用pew,或者add2virtualenv .如果您使用virtualenv和virtualenvwrapper的扩展,那么作为对此的变体.

  • 如果您始终喜欢sys.path上的当前工作目录,则可以始终PYTHONPATH=''在shell中导出.这是确保sys.path上的空字符串,python将其解释为当前工作目标.但这可能存在安全隐患.

  • 我自己最喜欢的黑客,滥用py.test如何加载conftest文件:conftest.py在项目的顶级目录中放空.

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

  • conftest.py黑客是个好主意!太糟糕了,这是一种虐待,如果它可能会消失:( (6认同)
  • 安装一些东西来运行测试???使用更多工具只是为了让测试运行器工作???操作 Python 路径,这是从不推荐的,并且在项目中移动某些内容时必须再次更改??? - 不!添加一个空文件似乎是最简单的解决方案!我不知道它为什么起作用,但我很高兴它起作用了。其他选项似乎是错误的,直到有人向我解释为什么我需要安装一些东西来测试它之前,当我已经拥有所有代码时。 (3认同)
  • 只是为与我处于相同情况的其他人提供一些确认,并慢慢变得疯狂:对于某些项目,这些黑客(`__init__.py`或`conftest.py`)实际上都不起作用,唯一让 pytest 高兴的是问题中显示。您可以调整相对导入以使 pytest 运行,但是当在 pytest 的*外部*运行程序时,它不起作用。为什么 pytest 不能简单地使用与 python 相同的 PYTHONPATH ?除了造成这样的情况之外,**到底**有什么意义让它变得不同?! (3认同)
  • 补充一点:如果您没有virtualenv,则可以使用“ python setup.py development”达到相同的效果。 (2认同)
  • @Zelphir 至于你为什么要先安装一些东西来测试它,好吧,你可以把它看作是一种测试*安装程序*本身的方法。如果没有这一步,完全有可能有一个通过的测试套件,但安装程序却损坏了(你最终会不小心发布一个损坏的包)。 (2认同)

sle*_*cal 9

其实答案是很容易,因为看到这里.

您需要做的就是__init__.py在测试目录及其每个子目录中添加一个,就像这样;

tests/__init__.py
tests/functional/__init__.py
tests/unit/__init__.py
Run Code Online (Sandbox Code Playgroud)

  • -1因为在[pytest docs]的["良好做法"部分]中明确表示不这样做**(http://doc.pytest.org/en/latest/goodpractices.html). (9认同)
  • 这实际上向包中添加了测试。这可能并不总是令人满意的。 (2认同)
  • @BrianBruggeman,我认为 setup.py 中的 `packages=find_packages(exclude=['contrib', 'docs', 'tests'])` 可以解决这个问题?@wim,该文档现在提供了两种场景 - 在应用程序包的**内部**或**外部**进行测试,所以我认为这现在是一个有效的选项? (2认同)
  • @AlenSiljak实际上,仍然鼓励“<repo>/tests”,并且不鼓励在代码结构中使用“tests”文件夹。我遇到的 pytest 的一些插件仍然存在不一致的行为(我主要使用coverage、isort、flake8)。也就是说,我已经开始将单元测试放在代码库中的“tests”文件夹中,并将集成/系统级测试放在顶部 <repo>/tests 文件夹中,这对我来说效果很好。 (2认同)

A H*_*A H 8

运行引用单个/多个包的 pytest

1 包

PYTHONPATH=$(pwd)/mypkg/ python3 -m pytest 
# or
PYTHONPATH=$(pwd)/mypkg/ python3 -m pytest  path/to/tests
Run Code Online (Sandbox Code Playgroud)

适用于 2 包(pkg1 pkg2)

# Use ; as a separator in windows
PYTHONPATH=/path/to/pkg1/:/path/to/pkg2/ python3 -m pytest tests
Run Code Online (Sandbox Code Playgroud)


A H*_*A H 5

最简单的方法是在terminal / cmd更改目录到父目录的位置(例如,在这种情况下cd C:/.../my_project)。

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

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

  • +1 这是一个合法且有记录的功能,而不仅仅是一个意外。请参阅 https://docs.pytest.org/en/latest/pythonpath.html#invoking-pytest-versus-python-m-pytest (4认同)
  • 值得关注该链接,它解释了“python -m pytest”在这一方面与普通“pytest”的行为不同。 (3认同)