我应该如何构建一个pytest测试包呢?

时间:2018-01-05 10:15:51

标签: python testing pytest

我的用例是远程(RESTful API等)测试整个系统的子系统。这意味着“pytest test only package”对生产代码没有任何依赖性(意味着其他生产代码python包)。

我创建了一个python包,它只包含测试相关的东西,如pytest测试,pytest fixtures,util模块中的测试帮助函数,pytests conftest.py,pytests pytest.ini等。它不包含任何生产代码相关的东西。

现在功能正在运行,但包的结构非常“hacky”。这意味着安装无法正常工作(测试,夹具和conftest文件未通过site_packages正确安装到MANIFEST.ini),并且必须“手动”完成软件包的部署。

在pytest文档中,我刚刚找到了有关如何构建包含production和pytest测试代码的包的最佳实践:Tests outside application codeTests as part of application codeTest directory structure

  1. 我应该如何构建一个只包含测试代码的python包?是否有其他包装结构(优点,缺点)?
  2. 应将测试文件及其依赖项(固定装置,帮助程序等)安装到哪里?
  3. 可能的解决方案2.: avocado-framework setup.py中将example tests部署为data filesDependent on the configuration默认情况下,测试会部署到/usr/share/avocado/tests

1 个答案:

答案 0 :(得分:2)

要求

我认为,您有三个要求:

  1. 安装的测试应该很容易被发现
  2. 为了开发目的,测试仍应在本地运行
  3. 在开发模式和安装模式下运行测试应产生相同的结果
  4. 项目结构

    考虑到这一点,我将如何构建项目:创建一些虚拟包(但具有唯一可区分的名称)并将测试目录放在那里,以及 import itertools min_length = 2 max_length = 5 s = 'ABCDEF' for i in range(min_length, max_length): print('length', i, 'cominations') print([_ for _ in itertools.combinations(s, i)]) 和实用程序模块。这是它的样子:

    conftest.py

    project/ ├── setup.py └── mypkg/    ├── __init__.py    └── tests/       ├── conftest.py       ├── utils.py       ├── other_utils.py       ├── test_spam.py       ├── test_eggs.py       └── other_tests/ # if you need to further grouping of tests       ├── conftest.py # if you need special conftest for other tests       └── test_bacon.py

    setup.py

    有了这个项目结构:

    1. from setuptools import setup setup( name='mypkg-tests', version='0.1', install_requires=['pytest'], packages=['mypkg'], package_data={'mypkg': ['tests/*', 'tests/**/*']}, ) dir:

      中正确发现并执行测试
      project/
    2. 当您构建源tar或wheel并安装软件包时,通过提供软件包名称可以轻松运行测试:

      $ pytest -v
      ============================= test session starts =============================
      platform darwin -- Python 3.6.3, pytest-3.3.2, py-1.5.2, pluggy-0.6.0 -- /Users
      /hoefling/.virtualenvs/stackoverflow/bin/python
      cachedir: .cache
      rootdir: /Users/hoefling/projects/private/stackoverflow/so-48111426, inifile:
      plugins: forked-0.2, asyncio-0.8.0, xdist-1.22.0, mock-1.6.3, hypothesis-3.44.4
      collected 3 items
      
      spam/tests/test_eggs.py::test_foo PASSED                                 [ 33%]
      spam/tests/test_spam.py::test_bar PASSED                                 [ 66%]
      spam/tests/other_tests/test_bacon.py::test_baz PASSED                    [100%]
      
      ========================== 3 passed in 0.03 seconds ===========================
      

      您将获得完全相同的测试结果,因为$ pytest -pyargs mypkg ... 发现测试的方式与在本地运行测试的方式相同,而不是扫描当前工作目录,包的目录将是扫描。

    3. 虽然所有测试以及config和utils都安装在pytest中,但它们本身不是包或模块。对于外部世界,分发仅包含空包site-packages; mypkg中的任何内容都不可导入,只有tests/可见。

    4. 为什么pytest不可靠

      当然,您可以在设置脚本中声明类似的内容:

      data_files

      首先,创建和维护要包含的测试列表并不方便(尽管可以使用setup( ... data_files=[ ('tests', ['tests/test_spam.py', 'tests/test_eggs.py']), # etc ] ) 编写某种自定义测试查找或者os.walk或其他)。但更重要的是,您无法将pathlib.glob可靠地安装到绝对路径上。我想在这里详细介绍一下;请随时查看my other answer以获取更多信息 - 但基本上,data_files包会将wheeldata_files中的每个绝对路径相对化,即使你构建了一个源代码分发,sys.prefix将首先构建一个轮子,然后安装轮子。因此,如果要从已安装的软件包运行测试,首先需要确定pip install并自行构建路径:

      sys.prefix

      避免$ SYS_PREFIX=$(python -c "import sys; print(sys.prefix)") $ pytest -v $SYS_PREFIX/whatever/dir/mapped/in/data_files/tests 问题的唯一方法是构建源代码分发并使用wheel进行安装。此选项将强制pip install mypkg --no-binary=mypkg跳过车轮构建步骤并直接从源安装。只有这样,测试才会安装到绝对路径上。我发现它非常不方便,因为有时你会忘记pip arg,并会花时间寻找错误源。或者有人必须安装包,而你不在那里指导他,并且无法运行测试。只是不要使用no-binary