在非根 conftest.py 中使用 pytest_addoptions

Mad*_*ist 6 python testing pytest

我有一个具有以下结构的项目:

Project/
|
+-- src/
|   |
|   +-- proj/
|       |
|       +-- __init__.py
|       +-- code.py
|       +-- tests/
|           |
|           +-- __init__.py
|           +-- conftest.py
|           +-- test_code.py
+-- doc/
+-- pytest.ini
+-- setup.py
Run Code Online (Sandbox Code Playgroud)

可导入的包proj位于该src目录下。测试与它一起安装在proj.tests子包中。代码、测试本身和安装都可以正常工作。但是,我无法将选项传递给测试。

我有一个选项,--plotsconftest.py(下Project/src/proj/tests/)中定义,它.plots/在根文件夹中创建一个文件夹并在那里放置一些图形调试:

# conftest.py
def pytest_addoption(parser):
    parser.addoption("--plots", action="store_true", default=False)
Run Code Online (Sandbox Code Playgroud)

我想有两种不同的方式来运行这个测试:

  1. 第一个是从命令行,在Project目录中:

     $ pytest --plots
    
    Run Code Online (Sandbox Code Playgroud)

    这立即失败

     usage: pytest [options] [file_or_dir] [file_or_dir] [...]
     pytest: error: unrecognized arguments: --plots
       inifile: /.../Project/pytest.ini
       rootdir: /.../Project
    
    Run Code Online (Sandbox Code Playgroud)

    如果我添加包目录,运行正常:

     $ pytest src/proj --plots
     ...
     rootdir: /.../Project, inifile: pytest.ini
     ...
    
    Run Code Online (Sandbox Code Playgroud)

    如果我指定测试子目录,它也很顺利:

     $ pytest src/proj/tests --plots
     ...
     rootdir: /.../Project, inifile: pytest.ini
     ...
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第二种方式是运行test包本身的功能。该test功能在定义Project/src/proj/__init__.py是这样的:

     # __init__.py
    
     def test(*args, **kwargs):
         from pytest import main
         cmd = ['--pyargs', 'proj.tests']
         cmd.extend(args)
         return main(cmd, **kwargs)
    
    Run Code Online (Sandbox Code Playgroud)

    该功能旨在Project像这样安装后运行:

     >>> import proj
     >>> proj.test()
    
    Run Code Online (Sandbox Code Playgroud)

    一般来说,这工作正常,但如果我这样做

     >>> proj.test('--plots')
    
    Run Code Online (Sandbox Code Playgroud)

    我像往常一样得到同样的错误:

     usage:  [options] [file_or_dir] [file_or_dir] [...]
     : error: unrecognized arguments: --plots
       inifile: None
       rootdir: /some/other/folder
    
    Run Code Online (Sandbox Code Playgroud)

    对于这个测试,我跑了python setup.py develop然后cd'd to/some/other/folder` 以确保一切安装正确。

我的目标是当我传入--plots命令行选项时让两个选项都能正常工作。似乎我已经找到了选项 #1 的解决方法,即手动将其中一个包传递到pytest,但我什至不完全理解它是如何工作的(为什么我可以传入src/projsrc/proj/tests?)。

所以问题是,如何让 pytest 始终如一地运行我的测试包,以便选择正确的包conftest.py?我愿意考虑任何合理的替代方案,使我能够使该--plots选项在源代码(在来自 的 shell 中运行Project)版本和proj.test()版本中始终如一地工作。


作为参考,这是我的pytest.ini文件:

# pytest.ini

[pytest]
testpaths = src/proj/tests
confcutdir = src/proj/tests
Run Code Online (Sandbox Code Playgroud)

它似乎没有任何区别。

我在 Python 2.7、3.3、3.4、3.5、3.6 和 3.7(在 anaconda 中)上运行 pytest 3.8.0。在所有版本中,结果都是可重现的。

hoe*_*ing 6

从报价pytest_addoption文档

注意:conftest.py由于pytest 在启动期间如何发现插件,此功能应仅在位于测试根目录的插件或文件中实现。

...

请注意,在工具启动时pytest不会conftest.py在更深的嵌套子目录中找到文件。将conftest.py文件保存在顶级测试或项目根目录中通常是个好主意。

当您pytestProject目录调用时,pytest将其识别为根目录,因此会忽略addoption挂钩Project/src/proj/tests/conftest.py

如果您描述的项目结构是pytest_addopts必需的,我会将钩子 impl移动到单独的插件模块;这可以驻留在项目目录中的任何位置,例如Project/src/proj/tests/plugin_plots.py. 现在,如果你打电话

$ pytest -p src.proj.tests.plugin_plots
Run Code Online (Sandbox Code Playgroud)

addoption钩IMPL将被执行的Args将被正确地加入。

(您可能需要调整sys.path才能正确加载自定义插件模块,例如使用PYTHONPATH=. pytest -ppython -m pytest -p,或以可编辑模式安装项目等)

-p要不每次都输入arg,请将其持久化pytest.ini,例如

# pytest.ini
[pytest]
addopts=-p src.proj.tests.plugin_plots
Run Code Online (Sandbox Code Playgroud)

编辑:

以编程方式运行测试时,请增强 args 列表:

def test(*args, **kwargs):
    from pytest import main
    cmd = ['-p', 'proj.tests.plugin_plots', '--pyargs', 'proj.tests']
    cmd.extend(args)
    return main(cmd, **kwargs)
Run Code Online (Sandbox Code Playgroud)

应该工作得很好。

  • 我玩得越多,它就越能回答我所有的问题。谢谢 (2认同)