Python pytest 教程(您获得无错误代码的门票)

2023-10-15

pytest 是一个强大的 Python 测试框架,可让您轻松创建小型、简单的测试,同时可扩展以支持应用程序和库的复杂功能测试。

它为您提供了一个平台,通过将测试用例编写为函数来执行 Python 测试,从而减少代码和样板代码的数量。

它还可以轻松创建测试套件或测试用例集合,用于测试 Python 代码的特定方面。

此外,pytest 提供了处理测试中常见任务的工具,例如测试的设置和分组。

 

 

安装Python pytest

要开始使用 pytest,您首先需要安装它。您可以使用 pip 安装 pytest,pip 是标准库附带的 Python 包安装程序。

这是安装 pytest 的命令:


pip install pytest
  

运行此命令后,pytest 应该已安装在您的 Python 环境中,您可以通过检查已安装的 pytest 版本来验证这一点:


pytest --version
  

您可能会看到类似于以下内容的输出:


pytest 7.3.1
  

这说明pytest已经安装成功,安装的版本是7.3.1。

现在,您已准备好开始使用 pytest 来满足您的 Python 测试需求。

 

基本 pytest 术语

在深入研究 pytest 之前,我们首先了解一些基本术语:

  • 测试用例:这是一个测试单元。它检查对一组特定输入的特定响应。在 pytest 中,测试用例是一个以关键字开头的 Python 函数test.
  • 测试套件:这是测试用例、测试套件或两者的集合。它用于聚合应一起执行的测试。
  • 测试功能:它是测试特定代码单元的单个函数。
  • 单元测试:这是软件测试的一个级别,其中测试软件的各个单元/组件。目的是验证软件的每个单元是否按设计运行。 pytest 提供了一种在 Python 中进行单元测试的简单方法。
    这是一个测试套件的示例,它由两个测试用例(测试函数)组成:

import pytest
def test_addition():
    assert 1 + 1 == 2
def test_subtraction():
    assert 3 - 2 == 1
  

运行此测试套件时,pytest 识别两个测试函数并运行它们。输出可能是:


test_module.py::test_addition PASSED
test_module.py::test_subtraction PASSED  

此输出表明我们的测试套件中的两个测试函数都通过了各自的测试。

 

Pytest 命名约定

pytest中的命名约定不仅是为了保持代码的一致性和整洁,也是为了确保测试发现机制的功能。

pytest 框架利用这些约定来自动识别和运行测试。

以下是 pytest 中使用的一些基本命名约定:

测试文件

pytest 中的测试发现过程从查找测试文件开始。按照惯例,所有测试文件都应命名为test_*.py or *_test.py。 Pytest 会自动将它们识别为包含测试的文件。

测试功能和方法

同样,所有测试函数都应以test_, 例如,test_example()。如果您在类中定义测试方法,它们也应该遵循此命名约定。

测试班

定义测试类时,该类应以Test,并且不应该有__init__方法。例如,TestClassExample.

夹具功能

夹具功能提供固定的基线,以便测试可靠地执行并产生一致的结果。它们被命名为常规函数,但应该描述它们提供的特定状态。例如,def setup_database() or def login_client().

尽管 pytest 不区分大小写,但 Python 命名约定建议使用小写单词并用下划线分隔。这对于保持测试文件的可读性尤其重要。

请记住,遵循这些约定的重要性不仅仅是“规则”。正确命名您的测试和类有助于确保 pytest 能够正确发现并运行您的测试和固定装置。

 

运行你的第一个测试

创建测试函数后,导航到包含测试文件的目录并运行 pytest 命令。
例如,考虑以下测试用例:


import pytest
def test_addition():
    assert 1 + 1 == 2
  

要运行此测试,请导航到包含测试文件的目录并运行:


pytest -v
  

您应该看到类似于以下内容的输出:


============================= test session starts ==============================
...

test_module.py::test_addition PASSED

========================== 1 passed in 0.03 seconds ===========================
  

“1 通过”消息是总体状态报告,指示通过的测试数量。

The -v命令行选项代表 verbose,意味着 pytest 将输出更详细的报告。

命令行选项

  1. Specifying tests
    • -k EXPRESSION:运行与给定关键字表达式匹配的测试。
    • -m MARKEXPR:仅运行与给定标记表达式匹配的测试。
  2. Test session
    • -x, --exitfirst:第一次出错或测试失败时立即退出。
  3. Output
    • -s:在输出中显示打印语句(默认情况下,pytest捕获输出)。
    • -v, --verbose:增加详细程度。
    • -q, --quiet:减少冗长。
  4. Test execution
    • --ff, --failed-first:运行所有测试,但首先运行最后一次失败的测试。
    • -n numprocesses:‘–dist=each –tx=NUM*popen’的快捷方式,其中 NUM 指的是要使用的核心数量。这来自于pytest-xdist用于并行执行的插件。
  5. Reporting
    • --html=path:创建测试结果的 HTML 报告。这需要pytest-html

 

pytest 函数剖析

pytest 函数是一个以单词开头的 Python 函数test_.

这就是 pytest 识别其测试的方式。这是 pytest 函数的一个简单示例:


import pytest
def test_addition():
    assert 1 + 1 == 2
  

在此测试函数中,我们使用assert关键字来指定我们要测试的条件。如果条件是True,测试通过;如果False,测试失败并提供失败的详细信息。
使用 pytest 运行此函数将输出:


============================= test session starts ==============================
...

test_module.py::test_addition PASSED

========================== 1 passed in 0.03 seconds ===========================
  

输出提供了一个状态报告,显示了我们的测试功能test_addition已经过去了。
The assert与其他测试框架相比,关键字是 pytest 可以编写更少代码的原因之一。

 

使用断言

在 pytest 中,断言是由assert语句,它检查给定的逻辑表达式是否为真。如果不正确,测试将失败。
这是在 pytest 函数中使用断言的示例:


import pytest
def test_multiplication():
    assert 2 * 3 == 6
  

使用 pytest 运行此测试函数,输出将是:


============================= test session starts ==============================
...

test_module.py::test_multiplication PASSED

========================== 1 passed in 0.03 seconds ===========================
  

在这个测试函数中,assert语句用于检查 2 乘以 3 是否等于 6。

事实上,测试通过了,并且 pytest 为我们提供了该测试的“PASSED”输出。
但是,如果断言是错误的,pytest 将提供有用的失败解释。例如,让我们改变我们的测试函数:


import pytest
def test_multiplication():
    assert 2 * 3 == 7
  

使用 pytest 运行此测试函数,输出将是:


============================= test session starts ==============================
...

test_module.py::test_multiplication FAILED

================================ FAILURES =================================
______________________________ test_multiplication ______________________________

    def test_multiplication():
>       assert 2 * 3 == 7
E       assert (2 * 3) == 7

test_module.py:4: AssertionError
========================== 1 failed in 0.03 seconds ===========================
  

在这种情况下,pytest 准确显示断言失败的位置和原因,并提供失败的详细信息。这使得调试和修复测试变得更加容易。

 

使用 pytest 标记

Pytest 标记允许我们轻松地在测试函数上设置元数据,例如将测试标记为预期失败,或者在某些条件下应跳过它们。

跳过测试

例如,您可以使用skip标记跳过特定测试:


import pytest

@pytest.mark.skip(reason="Skip this test")
def test_addition():
    assert 1 + 1 == 2
  

当您使用 pytest 运行此测试时,输出将是:


============================= test session starts ==============================
...

test_module.py::test_addition SKIPPED

========================== 1 skipped in 0.02 seconds ===========================
  

预期失败

The xfail标记表明测试预计会失败:


import pytest

@pytest.mark.xfail
def test_failed_addition():
    assert 1 + 1 == 3
  

使用 pytest 运行它,输出将是:


============================= test session starts ==============================
...

test_module.py::test_failed_addition XFAIL

========================== 1 xfailed in 0.02 seconds ===========================
  

标记和过滤测试

您还可以创建自己的自定义标记。例如,您可以将某些测试标记为仅在特定平台上运行:


import pytest
import sys

@pytest.mark.windows
def test_windows_only_behavior():
    assert sys.platform == 'win32'

@pytest.mark.linux
def test_linux_only_behavior():
    assert sys.platform == 'linux'
  

然后,您可以仅运行具有特定标记的测试:


pytest -m windows
  

The -mflag 允许您运行用给定标记名称标记的测试。

 

处理pytest中的异常

pytest 提供了多种方法来断言引发异常。实现这一点的主要工具是pytest.raises函数,可用于测试某段代码是否引发特定异常。
举个例子:


import pytest
def test_division_by_zero():
    with pytest.raises(ZeroDivisionError):
        num = 1 / 0
  

在此测试函数中,我们正在测试除以零会产生ZeroDivisionError。使用 pytest 运行它会输出:


============================= test session starts ==============================
...

test_module.py::test_division_by_zero PASSED

========================== 1 passed in 0.03 seconds ===========================
  

测试是成功的,因为除以零确实会产生ZeroDivisionError.

测试警告

要测试警告,您可以使用pytest.warns。这是一个例子:


import pytest
import warnings

def test_warning():
    with pytest.warns(UserWarning):
        warnings.warn("This is a warning!", UserWarning)
  

当您使用 pytest 运行此测试时,输出将是:


============================= test session starts ==============================
...

test_module.py::test_warning PASSED

========================== 1 passed in 0.03 seconds ===========================
  

在此测试中,我们检查我们的代码是否发出UserWarning。测试成功,因为我们的代码确实发出了UserWarning.
这些是 pytest 帮助测试异常和警告的一些方法。

 

pytest 夹具

pytest 夹具是在应用它的每个测试函数之前运行的函数。当我们想在每个测试方法之前运行一些代码时,就会使用夹具。
让我们从一个简单的装置开始:


import pytest

@pytest.fixture
def input_value():
    input = 39
    return input

def test_division(input_value):
    assert input_value % 3 == 0
  

在这里,我们定义了一个固定功能input_value()返回值 39。然后我们在中使用这个装置test_division()将其作为参数传递。

pytest 知道input_value是一个固定装置并调用它,然后将返回值传递给测试。
使用 pytest 运行将输出:


============================= test session starts ==============================
...

test_module.py::test_division PASSED

========================== 1 passed in 0.03 seconds ===========================
  

使用内置 pytest 夹具

pytest 还提供了几个内置装置。例如,tmpdirFixture 提供了测试调用所特有的临时目录:


def test_create_file(tmpdir):
    p = tmpdir.mkdir("sub").join("hello.txt")
    p.write("content")
    assert p.read() == "content"
  

夹具范围

夹具功能的范围可以通过提供scope参数到@pytest.fixture装饰师。

例如,如果您想创建一个每个模块初始化一次的固定装置,您可以使用module scope:


import pytest

@pytest.fixture(scope="module")
def input_value():
    input = 39
    return input
  

该装置每个模块仅执行一次。其他可能的值scope are function, class, and session.

 

pytestconftest.py

conftest.py是一个本地插件,用于共享固定功能、挂钩、插件和 pytest 的其他配置。

它会被 pytest 自动发现,因此您无需将其导入到测试文件中。名字conftest代表配置测试。

conftest.py应位于项目的根目录或包含测试文件的目录中。 pytest 会找到conftest.py测试收集时的文件。

一种常见的用法是conftest.py is to 存储 pytest 夹具函数可以在多个测试文件中使用。例如,考虑以下固定功能:


# conftest.py
import pytest

@pytest.fixture
def csv_data():
    return [
        {"name": "John", "age": 30, "job": "developer"},
        {"name": "Jane", "age": 25, "job": "designer"},
    ]
  

This csv_data固定装置现在可以在同一目录中的任何测试文件中使用conftest.py或任何子目录。这是使用此夹具的测试文件的示例:


# test_sample.py
def test_csv_data(csv_data):
    for row in csv_data:
        assert isinstance(row["name"], str)
        assert isinstance(row["age"], int)
        assert isinstance(row["job"], str)
  

使用 pytest 运行这个测试,你会发现csv_data夹具来自conftest.py自动使用:


============================= test session starts ==============================
...

test_sample.py::test_csv_data PASSED

========================== 1 passed in 0.03 seconds ===========================
  

 

将测试分组到班级

pytest 允许您将多个测试分组,这些测试都做出类似的断言到一个类中。这有助于让您的测试井井有条,并允许您共享设置或夹具代码。
以下是如何使用类对测试进行分组的示例:


import pytest
class TestMathOperations:
    def test_addition(self):
        assert 1 + 1 == 2
    def test_subtraction(self):
        assert 3 - 2 == 1
  

使用 pytest 运行它,输出将如下所示:


============================= test session starts ==============================
...

test_module.py::TestMathOperations::test_addition PASSED
test_module.py::TestMathOperations::test_subtraction PASSED

========================== 2 passed in 0.04 seconds ===========================
  

在输出中,我们看到两个测试都已被识别并在以下环境下运行TestMathOperations测试课。这样,随着我们的测试套件的增长,我们可以保持测试结构良好且可维护。

 

参数化测试

pytest 中的参数化测试允许您使用不同的参数多次运行测试函数。这是使用以下方法完成的@pytest.mark.parametrize装饰师。

参数化有助于测试函数针对各种输入和预期结果的行为,而无需编写多个测试用例。
这是参数化测试的一个简单示例:


import pytest

@pytest.mark.parametrize("test_input,expected", [(3, 9), (2, 4), (6, 36)])
def test_calc_square(test_input, expected):
    assert test_input**2 == expected
  

在这个例子中,test_calc_square运行了三遍。每次,它都会使用一组不同的值test_input and expected.
使用 pytest 运行将输出:


============================= test session starts ==============================
...

test_module.py::test_calc_square[3-9] PASSED
test_module.py::test_calc_square[2-4] PASSED
test_module.py::test_calc_square[6-36] PASSED

========================== 3 passed in 0.04 seconds ===========================
  

输出中的每一行代表一个带有一组不同参数的测试函数调用。

这项技术对于减少测试中的样板代码数量并使它们更具可读性和可维护性非常有用。

 

pytest 模拟

有时在单元测试中,我们希望替换被测系统的某些部分,以将其与系统的其余部分隔离。

这个过程称为mocking,Python的标准库,unittest.mock,为其提供了强大的框架。
以下是如何在 pytest 中使用模拟的示例:


from unittest.mock import MagicMock
import pytest
def test_magic_mock():
    mock = MagicMock()
    mock.__str__.return_value = 'foobarbaz'
    assert str(mock) == 'foobarbaz'
  

在这个例子中,我们创建一个MagicMock实例并指定返回值__str__方法被调用。

然后测试断言此行为按预期工作。使用 pytest 运行此测试,输出将是:


============================= test session starts ==============================
...

test_module.py::test_magic_mock PASSED

========================== 1 passed in 0.03 seconds ===========================
  

 

pytest 配置(通过 pytest.ini)

可以通过名为的配置文件将 pytest 配置为设置默认行为和变量pytest.ini.

该文件需要位于项目的根目录中,pytest会自动发现并使用它。
这是一个例子pytest.ini file:


[pytest]
minversion = 7.0
addopts = -ra -q
testpaths =
    tests
  

在这个例子中,minversion指定运行测试所需的最低 pytest 版本。addopts是 pytest 在运行时默认使用的附加选项。

Here, -ra意味着 pytest 将在测试会话结束时打印所有未通过测试的摘要,并且-q意味着 pytest 将减少冗长。

testpaths是 pytest 将查找测试的目录列表。
当您的测试套件的大小和复杂性不断增加时,此文件非常有用,因为它可以存储 pytest 的默认行为和配置,从而使您的测试过程更加高效。

 

生成测试报告

使用 pytest 运行测试后,生成结果报告通常很有帮助。 pytest 允许您使用各种插件来做到这一点。
pytest-html 就是这样的插件之一,它会生成 HTML 报告。您可以使用 pip 安装它:


pip install pytest-html
  

安装后,您可以使用以下命令生成 HTML 报告--html option:


pytest --html=report.html
  

运行此命令将在当前目录中创建一个名为“report.html”的 HTML 报告。

该报告将提供每个失败测试用例的失败细目、测试会话的总体状态报告以及各种其他信息。
另一个有用的插件是 pytest-cov,它提供测试覆盖率报告:


pip install pytest-cov
  

安装后,您可以使用它生成覆盖率报告:


pytest --cov=myproject
  

此命令将输出“myproject”目录的覆盖率报告,指示测试会话期间执行的代码的百分比。
这些只是 pytest 如何生成有用报告的几个示例。

 

Pytest 插件

pytest 插件是扩展 pytest 功能的一种方式。这些插件可以使用 pip 从 Python 包索引 (PyPI) 安装,并通过简单地将它们导入到测试代码中或在命令行上指定它们来使用。
以下是安装 pytest-xdist 插件的方法,该插件允许并行和分布式测试:


pip install pytest-xdist
  

要使用该插件,您可以在运行 pytest 时在命令行中指定它:


pytest -n 4
  

在此命令中,-n是 pytest-xdist 提供的一个选项,并且4是用于测试的 CPU 核心数。

流行的 pytest 插件

一些流行的 pytest 插件包括:

  • pytest-xdist:用于并行和分布式测试。
  • pytest-cov:用于测量测试覆盖率。
  • pytest-mock:为了更方便地使用unittest.mock module.
  • pytest-html:用于生成 HTML 报告。

您还可以编写自己的 pytest 插件。 pytest 插件只是一个定义一个或多个钩子函数的 Python 包。

这是一个简单插件的示例,它在测试会话开始时打印一条消息:


# content of myplugin.py
def pytest_sessionstart():
    print("Starting test session")
  

要使用此插件,您可以使用以下命令在命令行上指定它-p option:


pytest -p myplugin  

 

结论

我们涵盖了广泛的主题,从 pytest 的基础知识到更高级的功能,如固定装置、参数化、模拟和插件。

我希望本教程对您有所帮助,并帮助您为 Python 项目编写可靠的测试。

请记住,良好的测试对于维护高质量代码和及早发现问题至关重要。

测试愉快!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python pytest 教程(您获得无错误代码的门票) 的相关文章

随机推荐

  • Python GUI 示例(Tkinter 教程)

    在本教程中 我们将通过使用 Tkinter 包编写一些 Python GUI 示例来学习如何开发图形用户界面 Tkinter 包作为标准包随 Python 一起提供 因此我们不需要安装任何东西即可使用它 Tkinter 包是一个非常强大的包
  • Python 中的凯撒密码(文本加密教程)

    密码学涉及将一条信息 以纯文本形式 加密或编码为一种看起来乱码且在普通语言中毫无意义的形式 此编码消息 也称为密文然后 目标接收者可以使用传达给最终用户的解码技术 通常与私钥一起 将其解码回纯文本 凯撒密码是我们将在本教程中重点介绍的最古老
  • 安装和使用非 Composer Laravel 包

    如果你想在 Laravel 中使用包 你只需在 Composer json 文件中添加一行即可完成工作 这是因为该包在 packagist org 中可用 如果您要使用的包是非 Composer Laravel 包怎么办 可能在 git 存
  • 文本处理中 Awk 命令的 30 个示例

    在上一篇文章中 我们谈到了sed命令我们看到了许多在文本处理中使用它的例子 我们看到了它在这方面的优点 但它有一些局限性 有时您需要一些强大的功能 让您能够更好地控制数据处理 这是哪里awk 命令进来 awk 命令或具体的 GNU awk
  • 安装、保护、访问和配置 Linux 邮件服务器 (Postfix)

    如果您想发送或接收电子邮件 您应该有一个邮件服务器 在这篇文章中 我们将讨论 Linux 邮件服务器以及 SMTP 简单邮件传输协议 以及其他邮件相关协议 例如邮局协议 POP 和互联网消息访问协议 IMAP 的工作原理以及它们之间的关系他
  • 了解和使用 Linux Subshel​​l(实用指南)

    子shell是由shell启动的子进程 shell本质上是一个命令行解释器 它共享父 shell 的属性 但在单独的进程空间中运行 子 shell 为执行命令和运行脚本提供了隔离性和灵活性 子 shell 通常用于任务自动化 并行执行和模块
  • 加速您的 Python 代码:Numba 实用指南

    Numba 是一个开源 JIT 编译器 可以翻译以下代码的子集Python and NumPy代码转换为快速机器代码 它通过使用行业标准的 LLVM 编译器库并优化执行速度来加速数值计算 在本教程中 我们将探索如何使用 Numba 使 Py
  • Linux 正则表达式教程(Sed 和 AWK)示例

    为了成功地与Linux sed编辑和awk 命令在 shell 脚本中 您必须了解正则表达式或简称正则表达式 由于正则表达式有很多引擎 我们将使用 shell 正则表达式并了解 bash 在使用正则表达式方面的强大功能 首先 我们需要了解什
  • 10 多个在 Linux 中终止进程的示例

    在本教程中 我们将通过多个示例讨论如何终止 Linux 中的进程 在大多数情况下 就像输入 kill 命令然后输入进程 ID 通常缩写为 PID 一样简单 正如你所看到的 我们杀死了一个ID为1813的进程 如果您是 Windows 用户
  • 如何安装和配置 Squid Linux 代理服务器

    Linux代理服务器或代理服务器通常是保存访问过的网页以供以后请求的服务器 因此如果您尝试访问同一个网页或其他任何人 您将从代理服务器获取页面 这非常有用 它使网上冲浪速度更快并减少流量 这意味着成本更低 缓存服务器可以将外部流量减少至 4
  • 使用 Sed 命令进行文本替换的实际示例

    在本教程中 您将深入研究如何使用实际示例sed命令可用于文本替换 在本教程结束时 您将对以下方面有更深入的了解sed及其在文本替换中的实际应用 目录 hide 1 将 URL 中的 HTTP 更改为 HTTPS 2 用下划线替换空格 3 更
  • 数据帧过滤:在 Pandas 查询中使用正则表达式

    The 查询 方法Pandas 中允许您根据查询表达式过滤 DataFrame 行 将正则表达式 regex 的强大功能与query 方法允许更高级和灵活的查询 本教程将指导您完成使用正则表达式的过程query 熊猫中的方法 目录 hide
  • 使用 to_xml 将 Pandas DataFrame 转换为 XML 文件

    The to xml方法允许您将 DataFrame 转换为 XML 格式 在本教程中 我们将逐步完成导出Pandas使用 DataFrame 到 XML 文件to xml method 目录 hide 1 Pandas to xml 语法
  • 使用 to_csv 将 Python Pandas DataFrame 导出到 CSV 文件

    The to csv函数允许您从a写入数据PandasDataFrame 到 CSV 文件 当您需要保存 共享或导出数据以便在不同的环境或应用程序中进一步使用或分析时 这非常有用 它带有多个参数 可帮助您根据需要自定义流程 例如 您可以选择
  • 使用 Linux-PAM 增强 Linux 身份验证

    在上一篇文章中 我们讨论了Linux iptables 防火墙 还有人问认证问题 今天我们来聊聊Linux中用于身份验证的强大框架 那就是Linux PAM PAM or 可插拔的身份验证模块是位于 Linux 应用程序和 Linux 本机
  • Linux gzip 命令:综合教程

    gzip 代表 GNU zip 是基于 Unix 的系统上用于压缩和解压缩文件的流行工具 该工具不仅仅压缩单个文件 与其他工具 例如tar用于压缩目录 目录 hide 1 命令结构和选项 2 压缩和解压文件 3 了解 gzip 中使用的压缩
  • 使用 Pandas read_xml 将 XML 文件解析为 DataFrame

    The read xml函数于Pandas用于读取 XML 可扩展标记语言 文件并将其转换为 DataFrame 让我们深入研究实际示例来了解它是如何工作的 目录 hide 1 Pandas read xml 语法 2 Read from
  • Python 中的 JSON 操作和转换技术

    在本教程中 您将学习各种 JSON 处理技术 例如加载 JSON 对象 写入 排序 JSON 或解析 JSON 等 JSON 代表JavaScript Object N代表结构化数据的otation JSON 数据用于交换信息 在Pytho
  • 什么是 Linux 文件系统?简易指南

    您可能已经对 Linux 有一点了解 但您可能并不确切知道您的数据在幕后是如何处理的 因为如果你像许多其他 Linux 用户一样 你就会认为这些事情是理所当然的 但你的 Linux 文件系统可没这么无忧无虑 所以 今天我们要讨论的正是 Li
  • Python pytest 教程(您获得无错误代码的门票)

    pytest 是一个强大的 Python 测试框架 可让您轻松创建小型 简单的测试 同时可扩展以支持应用程序和库的复杂功能测试 它为您提供了一个平台 通过将测试用例编写为函数来执行 Python 测试 从而减少代码和样板代码的数量 它还可以