在非root用户的conftest.py

时间:2018-09-21 16:25:35

标签: python testing pytest

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

Project/
|
+-- src/
|   |
|   +-- proj/
|       |
|       +-- __init__.py
|       +-- code.py
|       +-- tests/
|           |
|           +-- __init__.py
|           +-- conftest.py
|           +-- test_code.py
+-- doc/
+-- pytest.ini
+-- setup.py

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

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

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

我有两种不同的方式必须运行此测试:

  1. 第一个是从命令行进入Project目录中的:

    $ pytest --plots
    

    此操作立即失败

    usage: pytest [options] [file_or_dir] [file_or_dir] [...]
    pytest: error: unrecognized arguments: --plots
      inifile: /.../Project/pytest.ini
      rootdir: /.../Project
    

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

    $ pytest src/proj --plots
    ...
    rootdir: /.../Project, inifile: pytest.ini
    ...
    

    如果我指定tests子目录,它也会很好:

    $ pytest src/proj/tests --plots
    ...
    rootdir: /.../Project, inifile: pytest.ini
    ...
    
  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)
    

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

    >>> import proj
    >>> proj.test()
    

    通常来说,这可以,但是如果可以,

    >>> proj.test('--plots')
    

    我得到和往常一样的错误:

    usage:  [options] [file_or_dir] [file_or_dir] [...]
    : error: unrecognized arguments: --plots
      inifile: None
      rootdir: /some/other/folder
    

    对于该测试,我先运行python setup.py develop,然后运行cd / {some / other / folder` to,以确保所有内容均正确安装。

我的目标是当我通过--plots命令行选项时使两个选项都能正常工作。看来我找到了方法#1的解决方法,该方法是将其中一个软件包手动传递给pytest,但我什至不完全了解它的工作原理(为什么我可以传递任一{{ 1}}或src/proj?)。

所以问题是,如何让pytest一致地运行我的测试包,以便正确的src/proj/tests被选中?我愿意考虑任何可行的替代方案,使我可以使conftest.py选项在源版本(在--plots的shell中运行)和Project版本中均能正常工作。


作为参考,这是我的proj.test()文件:

pytest.ini

似乎没有什么区别。

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

1 个答案:

答案 0 :(得分:1)

引用the pytest_addoption docs

  

注意:由于conftest.py discovers plugins during startup的方式,此功能仅应在位于测试根目录的插件或pytest文件中实现。

     

...

     

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

当您从pytest目录调用Project时,pytest将其识别为根目录,因此addoption中的Project/src/proj/tests/conftest.py钩子将被忽略。 / p>

如果您描述的项目结构是必需的,则将pytest_addopts钩子impl移至单独的插件模块;它可以驻留在项目目录中的任何位置,例如Project/src/proj/tests/plugin_plots.py。现在,如果您致电

$ pytest -p src.proj.tests.plugin_plots

addoption钩子impl将被执行,并且args将被正确添加。

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

要每次都不输入-p参数,请将其保留在pytest.ini中,例如

# pytest.ini
[pytest]
addopts=-p src.proj.tests.plugin_plots

编辑:

以编程方式运行测试时,增强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)

应该可以正常工作。