良好的集成实践¶
用PIP安装包¶
对于开发,我们建议您使用 venv 对于虚拟环境和 pip 用于安装应用程序和任何依赖项,以及 pytest
包装本身。这样可以确保代码和依赖项与系统python安装分离。
其次,放置一个 setup.py
文件位于包的根目录中,至少包含以下内容:
from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())
哪里 PACKAGENAME
是您的包裹的名称。然后,您可以在“可编辑”模式下安装软件包,方法是从同一目录运行:
pip install -e .
python setup.py develop
或 conda develop
它使用开发代码的符号链接来安装包。
Python测试发现的约定¶
pytest
实现以下标准测试发现:
如果未指定参数,则集合从开始
testpaths
(如果配置)或当前目录。或者,命令行参数可以用于目录、文件名或节点ID的任意组合。递归到目录中,除非它们匹配
norecursedirs
.在这些目录中,搜索
test_*.py
或*_test.py
文件,由其导入 test package name .从这些文件中收集测试项:
test
在类之外加前缀的测试函数或方法test
内置前缀测试函数或方法Test
带前缀的测试类(不带__init__
方法)
有关如何自定义测试发现的示例 更改标准(python)测试发现 .
在python模块中, pytest
同时发现使用标准的测试 unittest.TestCase 子类化技术。
选择测试布局/导入规则¶
pytest
支持两种常见的测试布局:
应用程序代码之外的测试¶
如果您有许多功能测试或出于其他原因希望将测试与实际应用程序代码分开(通常是一个好主意),那么将测试放入实际应用程序代码之外的额外目录可能会很有用:
setup.py
mypkg/
__init__.py
app.py
view.py
tests/
test_app.py
test_view.py
...
这有以下好处:
您的测试可以在执行后针对已安装的版本运行
pip install .
.您的测试可以在执行后使用可编辑的安装在本地副本上运行
pip install --editable .
.如果你没有
setup.py
文件和依赖于这样一个事实:默认情况下,python将当前目录放入sys.path
要导入包,可以执行python -m pytest
直接对本地副本执行测试,而不使用pip
.
注解
见 调用 pytest 对战 python -m pytest 有关呼叫之间差异的详细信息 pytest
和 python -m pytest
.
请注意,如果您正在使用 prepend
import mode (这是默认值):您的测试文件必须具有 独特名称 ,因为 pytest
将它们导入为 top-level 模块,因为没有要从中派生完整包名称的包。换句话说,上面示例中的测试文件将导入为 test_app
和 test_view
通过添加顶级模块 tests/
到 sys.path
.
如果需要具有相同名称的测试模块,可以添加 __init__.py
文件到您 tests
文件夹和子文件夹,将其更改为包:
setup.py
mypkg/
...
tests/
__init__.py
foo/
__init__.py
test_view.py
bar/
__init__.py
test_view.py
现在,pytest将模块加载为 tests.foo.test_view
和 tests.bar.test_view
,允许使用相同名称的模块。但现在这引入了一个微妙的问题:为了从 tests
目录,pytest将存储库的根目录 sys.path
这增加了现在 mypkg
也很重要。
如果您使用的工具 tox 在虚拟环境中测试包,因为您要测试 安装 包的版本,而不是存储库中的本地代码。
在这种情况下,它是 强烈地 建议使用 src
应用程序根包驻留在根目录的子目录中的布局:
setup.py
src/
mypkg/
__init__.py
app.py
view.py
tests/
__init__.py
foo/
__init__.py
test_view.py
bar/
__init__.py
test_view.py
这种布局可以防止许多常见的陷阱,并具有许多好处,这在这篇优秀的文章中可以更好地解释。 blog post by Ionel Cristian Mărieș .
注解
新的 --import-mode=importlib
(见 导入模式 )不存在上述缺点,因为 sys.path
和 sys.modules
在导入测试模块时不会更改,因此强烈建议遇到此问题的用户尝试它并报告新选项是否对他们有效。
这个 src
但是,仍然强烈建议使用目录布局。
测试作为应用程序代码的一部分¶
如果测试和应用程序模块之间有直接关系,并希望将它们与应用程序一起分发,则将测试目录内联到应用程序包中是很有用的:
setup.py
mypkg/
__init__.py
app.py
view.py
test/
__init__.py
test_app.py
test_view.py
...
在这个方案中,使用 --pyargs
选项:
pytest --pyargs mypkg
pytest
会发现哪里 mypkg
安装并从中收集测试。
请注意,此布局还与 src
上一节中提到的布局。
注解
可以为应用程序使用python3命名空间包(pep420),但pytest仍将执行 test package name 基于存在的 __init__.py
文件夹。如果您使用上述两种推荐的文件系统布局之一,但不使用 __init__.py
目录中的文件应该只适用于python3.3及更高版本。但是,从“内联测试”中,需要使用绝对导入来获取应用程序代码。
注解
在 prepend
和 append
导入模式,如果pytest发现 "a/b/test_module.py"
测试文件递归到文件系统时,它确定导入名称,如下所示:
决定
basedir
:这是第一个不包含__init__.py
. 如果两者兼而有之a
和b
包含一个__init__.py
文件,然后是的父目录a
将成为basedir
.执行
sys.path.insert(0, basedir)
使测试模块可以在完全限定的导入名称下导入。import a.b.test_module
其中路径由转换路径分隔符确定/
转换为“.”字符。这意味着您必须遵循将目录和文件名直接映射到导入名称的惯例。
这种有点进化的导入技术的原因是,在较大的项目中,多个测试模块可能互相导入,因此派生规范的导入名称有助于避免意外,例如测试模块被导入两次。
用 --import-mode=importlib
事情不那么复杂,因为pytest不需要改变 sys.path
或 sys.modules
,让事情不再那么令人惊讶。
托克斯¶
一旦您完成了您的工作,并希望确保您的实际包通过了您可能希望查看的所有测试 tox 虚拟环境测试自动化工具及其 pytest support . tox帮助您使用预定义的依赖项设置virtualenv环境,然后使用选项执行预先配置的测试命令。它将针对已安装的包运行测试,而不是针对源代码签出运行测试,这有助于检测包故障。