我应该如何构建一个 pytest 测试包?
How should I structure a pytest test only package?
我的用例是关于远程(RESTful API 等)测试整个系统的子系统。这意味着 "pytest test only package" 对生产代码没有任何依赖性(意味着其他生产代码 python 包)。
我创建了一个 python 包,它只包含测试相关的东西,如 pytest 测试、pytest fixtures、util 模块中的测试辅助函数、pytests conftest.py
、pytests pytest.ini
等。它不包含任何与生产代码相关的内容。
目前功能正常,但包的结构相当 "hacky"。这意味着安装工作不正常(测试、fixture 和 conftest 文件未通过 MANIFEST.ini
正确安装到 site_packages
)并且必须完成包的部署 "manually".
在 pytest 文档中,我刚刚找到了有关如何构建包含生产和 pytest 测试代码的包的最佳实践:Tests outside application code, Tests as part of application code and Test directory structure。
- 我应该如何构建只包含测试代码的 python 包?是否有替代的包结构(优点,缺点)?
- 测试文件及其依赖项(fixtures、helpers 等)应该安装到哪里?
2 的可能解决方案:avocado-framework 部署 example tests as data files in setup.py
. Dependent on the configuration 测试默认部署到 /usr/share/avocado/tests
。
要求
在我看来,您需要满足三个要求:
- 安装的测试应该很容易被发现
- 出于开发目的,测试仍应运行在本地可用
- 运行 开发模式和安装模式下的测试应该产生相同的结果
项目结构
考虑到这一点,我将如何构建项目:创建一些虚拟包(但具有唯一的可区分名称)并将测试目录以及 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
from setuptools import setup
setup(
name='mypkg-tests',
version='0.1',
install_requires=['pytest'],
packages=['mypkg'],
package_data={'mypkg': ['tests/*', 'tests/**/*']},
)
使用此项目结构:
在 project/
目录中本地正确发现和执行测试:
$ 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/Whosebug/bin/python
cachedir: .cache
rootdir: /Users/hoefling/projects/private/Whosebug/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 ===========================
当您构建源 tar 或 wheel 并安装包时,通过提供包名称可以轻松 运行 测试:
$ pytest -pyargs mypkg
...
您将获得完全相同的测试结果,因为 pytest
发现测试的方式与 运行 在本地进行测试的方式相同,只不过不是扫描当前工作目录,而是包的将扫描目录。
尽管所有测试以及配置和实用程序都安装在 site-packages
中,但它们本身不是包或模块。对于外界来说,分发包中只有一个空包mypkg
; tests/
中的任何内容都不可导入,并且仅对 pytest
.
可见
为什么data_files
不可靠
当然你可以在设置脚本中这样声明:
setup(
...
data_files=[
('tests', ['tests/test_spam.py', 'tests/test_eggs.py']), # etc
]
)
首先,创建和维护要包含的测试列表并不方便(尽管肯定可以使用 os.walk
或 pathlib.glob
或任何)。但更重要的是,您将无法可靠地将 data_files
安装到绝对路径。我想在这里详细介绍;随时查看 以获取更多信息 - 但基本上,它是 wheel
包相对化 data_files
到 sys.prefix
中的每个绝对路径,即使你构建了一个源distribution,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
跳过 wheel 构建步骤并直接从源安装。只有这样,测试才会安装到绝对路径。我觉得这很不方便,因为有时您会忘记 no-binary
arg,并且会花时间寻找错误源。或者有人必须在您不在时指导他安装软件包,并且将无法 运行 测试。根本不要使用 data_files
.
我的用例是关于远程(RESTful API 等)测试整个系统的子系统。这意味着 "pytest test only package" 对生产代码没有任何依赖性(意味着其他生产代码 python 包)。
我创建了一个 python 包,它只包含测试相关的东西,如 pytest 测试、pytest fixtures、util 模块中的测试辅助函数、pytests conftest.py
、pytests pytest.ini
等。它不包含任何与生产代码相关的内容。
目前功能正常,但包的结构相当 "hacky"。这意味着安装工作不正常(测试、fixture 和 conftest 文件未通过 MANIFEST.ini
正确安装到 site_packages
)并且必须完成包的部署 "manually".
在 pytest 文档中,我刚刚找到了有关如何构建包含生产和 pytest 测试代码的包的最佳实践:Tests outside application code, Tests as part of application code and Test directory structure。
- 我应该如何构建只包含测试代码的 python 包?是否有替代的包结构(优点,缺点)?
- 测试文件及其依赖项(fixtures、helpers 等)应该安装到哪里?
2 的可能解决方案:avocado-framework 部署 example tests as data files in setup.py
. Dependent on the configuration 测试默认部署到 /usr/share/avocado/tests
。
要求
在我看来,您需要满足三个要求:
- 安装的测试应该很容易被发现
- 出于开发目的,测试仍应运行在本地可用
- 运行 开发模式和安装模式下的测试应该产生相同的结果
项目结构
考虑到这一点,我将如何构建项目:创建一些虚拟包(但具有唯一的可区分名称)并将测试目录以及 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
from setuptools import setup
setup(
name='mypkg-tests',
version='0.1',
install_requires=['pytest'],
packages=['mypkg'],
package_data={'mypkg': ['tests/*', 'tests/**/*']},
)
使用此项目结构:
在
project/
目录中本地正确发现和执行测试:$ 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/Whosebug/bin/python cachedir: .cache rootdir: /Users/hoefling/projects/private/Whosebug/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 ===========================
当您构建源 tar 或 wheel 并安装包时,通过提供包名称可以轻松 运行 测试:
$ pytest -pyargs mypkg ...
您将获得完全相同的测试结果,因为
pytest
发现测试的方式与 运行 在本地进行测试的方式相同,只不过不是扫描当前工作目录,而是包的将扫描目录。尽管所有测试以及配置和实用程序都安装在
site-packages
中,但它们本身不是包或模块。对于外界来说,分发包中只有一个空包mypkg
;tests/
中的任何内容都不可导入,并且仅对pytest
. 可见
为什么data_files
不可靠
当然你可以在设置脚本中这样声明:
setup(
...
data_files=[
('tests', ['tests/test_spam.py', 'tests/test_eggs.py']), # etc
]
)
首先,创建和维护要包含的测试列表并不方便(尽管肯定可以使用 os.walk
或 pathlib.glob
或任何)。但更重要的是,您将无法可靠地将 data_files
安装到绝对路径。我想在这里详细介绍;随时查看 wheel
包相对化 data_files
到 sys.prefix
中的每个绝对路径,即使你构建了一个源distribution,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
跳过 wheel 构建步骤并直接从源安装。只有这样,测试才会安装到绝对路径。我觉得这很不方便,因为有时您会忘记 no-binary
arg,并且会花时间寻找错误源。或者有人必须在您不在时指导他安装软件包,并且将无法 运行 测试。根本不要使用 data_files
.