好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Pytest权威教程22-优质集成实践

目录

优质集成实践 使用pip安装包 Python测试发现的约定 选择测试布局结构/导入规则 在应用程序代码外测试 测试作为应用程序代码的一部分 tox

返回: Pytest权威教程

优质集成实践

使用pip安装包

对于开发,我们建议你将[venv来安装应用程序和任何依赖项,以及 pytest 包本身。这可确保你的代码和依赖项与系统Python安装隔离。

接下来, setup.py 使用以下最低内容将文件放在包的根目录中:

from setuptools import setup,find_packages

setup(name="PACKAGENAME",packages=find_packages())

PACKAGENAME 包裹的名称在哪里。然后,你可以通过从同一目录运行,以“可编辑”模式安装程序包:

pip install -e .

它允许你更改源代码(测试和应用程序)并随意重新运行测试。这与运行类似,或者使用符号链接将你的包安装到开发代码中。 pythonsetup.pydevelop``condadevelop

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
    ...

这有以下好处:

执行后,你的测试可以针对已安装的版本运行。 pipinstall. 执行后,你可以使用可编辑安装对本地副本运行测试。 pipinstall--editable. 如果你没有 setup.py 文件并且依赖于默认情况下Python将当前目录放入 sys.path 以导入你的包,则可以执行直接对本地副本执行测试,而不使用。 python-mpytest``pip

注意: 有关调用和调用之间差异的更多信息,请参阅[pytest导入机制和sys.path / PYTHONPATH。 pytest``python-mpytest

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

这种布局可以防止许多常见的陷阱,并且有很多好处,这在[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 。如果如两者 a 并 b 包含一个 __init__.py 文件,然后父目录 a 将成为 basedir 。 执行以使测试模块可以在完全限定的导入名称下导入。 sys.path.insert(0,basedir) importa.b.test_module 其中路径是通过将路径分隔符 / 转换为“。”字符来确定的。这意味着你必须遵循将目录和文件名直接映射到导入名称的约定。

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

tox

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

与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测试数据mand.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

片状”测试是表现出间歇性或偶发性失败的测试,似乎具有非确定性行为。有时它会通过,有时会失败,而且不清楚为什么。本页讨论了可以提供帮助的pytest函数以及识别,修复或减轻它们的其他一般策略。

查看更多关于Pytest权威教程22-优质集成实践的详细内容...

  阅读:27次