Pytest官方教程-23-优质集成实践

目录:

  1. 安装及入门
  2. 使用和调用方法
  3. 原有TestSuite使用方法
  4. 断言的编写和报告
  5. Pytest fixtures:清晰 模块化 易扩展
  6. 使用Marks标记测试用例
  7. Monkeypatching/对模块和环境进行Mock
  8. 使用tmp目录和文件
  9. 捕获stdout及stderr输出
  10. 捕获警告信息
  11. 模块及测试文件中集成doctest测试
  12. skip及xfail: 处理不能成功的测试用例
  13. Fixture方法及测试用例的参数化
  14. 缓存: 使用跨执行状态
  15. unittest.TestCase支持
  16. 运行Nose用例
  17. 经典xUnit风格的setup/teardown
  18. 安装和使用插件
  19. 插件编写
  20. 编写钩子(hook)方法
  21. 运行日志
  22. API参考
    1. 方法(Functions)
    2. 标记(Marks)
    3. 钩子(Hooks)
    4. 装置(Fixtures)
    5. 对象(Objects)
    6. 特殊变量(Special Variables)
    7. 环境变量(Environment Variables)
    8. 配置选项(Configuration Options)
  23. 优质集成实践
  24. 片状测试
  25. Pytest导入机制及sys.path/PYTHONPATH
  26. 配置选项
  27. 示例及自定义技巧
  28. Bash自动补全设置

使用pip安装包

对于开发,我们建议你将venv用于虚拟环境(或者用于Python 2.7的virtualenv),并使用 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 在课堂之外的前缀测试函数或方法
    • 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导入机制和sys.path / PYTHONPATHpytest``python -m pytest

请注意,使用此方案时,你的测试文件必须具有唯一的名称,因为pytest将它们作为顶级模块导入,因为 没有包来从中获取完整的包名称。换句话说,在上面的示例中的试验文件将被导入为test_apptest_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_viewtests.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

这种布局可以防止许多常见的陷阱,并且有很多好处,这在IonelCristianMărieş的优秀博客文章中有更好的解释 。

测试作为应用程序代码的一部分

如果测试和应用程序模块之间存在直接关系并希望将它们与应用程序一起分发,则将测试目录内联到应用程序包中非常有用:

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仍将根据文件的存在执行测试包名称发现__init__.py。如果你使用上面两个推荐的文件系统布局中的一个,但是__init__.py 从你的目录中删除它们,那么它应该适用于Python3.3及更高版本。但是,从“内联测试”开始,你将需要使用绝对导入来获取应用程序代码。

注意

如果pytest在递归到文件系统时找到“a / b / test_module.py”测试文件,它将确定导入名称,如下所示:

  • 确定basedir:这是第一个“向上”(朝向根)目录,不包含__init__.py。如果如两者ab包含一个__init__.py文件,然后父目录a将成为basedir
  • 执行以使测试模块可以在完全限定的导入名称下导入。sys.path.insert(0, basedir)
  • import a.b.test_module其中路径是通过将路径分隔符/转换为“。”字符来确定的。这意味着你必须遵循将目录和文件名直接映射到导入名称的约定。

这种有点进化的导入技术的原因在于,在较大的项目中,多个测试模块可能相互导入,因此导出规范的导入名称有助于避免出现意外情况,例如测试模块导入两次。

TOX

一旦完成了你的工作并希望确保你的实际软件包通过所有测试,你可能需要查看tox,virtualenv测试自动化工具及其pytest支持。tox帮助你使用预定义的依赖项设置virtualenv环境,然后使用选项执行预配置的测试命令。它将针对已安装的软件包运行测试,而不是针对源代码检查,从而有助于检测包装故障。

与setuptools集成

你可以使用pytest-runner插件将测试运行集成到基于setuptools的项目中。

将此添加到setup.py文件:

from setuptools import setup

setup(
    # ...,
    setup_requires=["pytest-runner", ...],
    tests_require=["pytest", ...],
    # ...,
)

并在setup.cfg文件中创建一个别名:

[aliases]
test=pytest

如果你现在输入:

python setup.py test

这将使用执行你的测试pytest-runner。因为这是一个独立版本,pytest无需事先安装,无论如何都需要调用test命令。你还可以使用其他参数传递给pytest,例如测试目录或其他选项--addopts

你还可以setup.cfg通过将文件放入以下[tool:pytest]部分来指定文件中的其他pytest-ini选项:

[tool:pytest]
addopts = --verbose
python_files = testing/*/*.py

手动整合

如果由于某种原因你不想/不能使用pytest-runner,你可以编写自己的setuptools测试命令来调用pytest。

import sys

from setuptools.command.test import test as TestCommand

class PyTest(TestCommand):
    user_options = [("pytest-args=", "a", "Arguments to pass to pytest")]

    def initialize_options(self):
        TestCommand.initialize_options(self)
        self.pytest_args = ""

    def run_tests(self):
        import shlex

        # import here, cause outside the eggs aren't loaded
        import pytest

        errno = pytest.main(shlex.split(self.pytest_args))
        sys.exit(errno)

setup(
    # ...,
    tests_require=["pytest"],
    cmdclass={"pytest": PyTest},
)

现在,如果你运行:

python setup.py test

这将pytest在需要时下载,然后按照你的预期运行测试。你可以使用--pytest-args-a命令行选项传递单个参数字符串。例如:

python setup.py test -a "--durations=5"

相当于运行 pytest --durations=5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容