当前位置 : 首页 » 文章分类 :  开发  »  Python-pytest

Python-pytest

Python 测试框架 pytest 使用笔记

Pytest 是 Python 一款三方测试框架,用于编写和运行单元测试、集成测试和功能测试。
Pytest 测试框架具有简单、灵活、易于扩展等特点,被广泛应用于 Python 项目的测试工作中。
Pytest 主要特点:

  • 简单易用:Pytest测试框架的API简单易用,可以快速编写测试用例。
  • 灵活多样:Pytest测试框架支持多种测试方式,包括函数式测试、类式测试、参数化测试、fixture测试等。
  • 插件机制:Pytest测试框架支持插件机制,可以通过插件扩展测试框架的功能。
  • 断言机制:Pytest测试框架支持多种断言方式,包括assert语句、assert关键字、assert表达式等。
  • 报告机制:Pytest测试框架支持生成多种测试报告,包括控制台报告、HTML报告、JUnit报告等。

安装 pytest

pip install pytest


修改 PyCharm 默认测试框架

安装 pytest 后,PyCharm 会自动检测到 pytest 并将 pytest 做为默认测试框架。
之后在所有 test_ 开头 或 _test 结尾的文件上点 run 或 debug 时都会走 pytest 测试框架。

也可以手动修改 PyCharm 的测试框架:
File -> Settings -> Tools -> Python Integrated Tools -> Testing -> Default test runner 设置
能看到 Default test runner 是 Autodetect(pytest),可以改为一个其他的测试框架比如 Unittests


测试文件/测试函数/测试类

直接执行 pytest 默认运行所有 test_*.py 或 *_test.py 文件中的测试用例:

规范
测试文件名以 test_ 开头或 test 结尾,如 test_sample.py
测试类名以 Test 开头,如 TestCalculator
测试方法以 test
开头,如 test_addition

测试函数:

def test_add(): # 测试函数需以test_开头
    """测试加法"""
    s = 1 + 2
    assert s == 3, f'断言失败, {s} != 3' # 断言

测试类:

class TestAdd:  # 测试类
      def test_add_01(self):  # 测试方法
          s = 1 + 2
          assert s == 3, f'断言失败, {s} != 3'  # 断言

执行测试:
pytest my_test.py

if __name__ == '__main__':
    import pytest
    pytest.main([__file__]) # pytest测试当前文件

pytest 的运行方式

例如有 test_pytest.py 内容如下:

from sys import argv

def test_argv():
    print('当前脚本名称:', argv[0])
    print('参数个数:', len(argv))
    print('参数列表:', argv)

if __name__ == '__main__':
    import pytest
    pytest.main(['-v -s'])

PyCharm 中点 Run/Debug 执行

PyCharm 中,只要默认的集成测试框架是 pytest(可通过 Python Integrated Tools -> Testing -> Default test runner 配置及查看 PyCharm 的默认集成测试框架)
在 test_argv() 测试函数上就会显示一个绿色的 Run/Debug 按钮,可直接点击运行测试函数。
同理,在测试文件、测试类上也都有绿色的 Run/Debug 按钮

PyCharm 中点 __main__ 函数执行

pytest test_xx.py 命令行执行


assert 断言

assert 普通断言 assert result == 5
pytest.raises 异常断言:

def test_divide_by_zero():
    with pytest.raises(ZeroDivisionError):
        1 / 0

参数化测试

通过 @pytest.mark.parametrize 实现多组输入输出验证:

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (5, -1, 4),
])
def test_add(a, b, expected):
    assert add(a, b) == expected

测试夹具(Fixtures)

用于测试前准备资源(如数据库连接、临时文件)和测试后置数据清理

测试类夹具

class TestAdd:  # 测试类
 def setup_class(self):
     print('测试类准备')

 def teardown_class(self):
     print('测试类清理')

覆盖 pytest_runtest_makereport 钩子

覆盖 pytest pytest_runtest_makereport 钩子,实现:

  • 在输出结果的 test_module.py::test_method PASSED [100%] 之后加一个换行,避免测试方法中的 print 与测试报告结果出现在同一行
  • 在测试方法的首个 print 输出前(如果有的话)加一行 === 测试方法 {method_name} 输出内容 ===
import pytest

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield  # 执行原始 pytest_runtest_makereport 钩子,获取返回值
    report = outcome.get_result()  # 测试报告对象

    if report.when == "call":
        modified_sections = []
        for header, content in report.sections:
            if header.startswith("Captured stdout") and content.strip():
                # 构建动态分隔线
                test_name = item.name
                separator = "=" * ((80 - len(test_name) - len("测试方法输出内容") - 4) // 2)
                title = f"{separator} 测试方法 {test_name} 输出内容 ".ljust(80, "=")
                stripped_content = content.lstrip('\n')
                new_content = f"\n{title}\n{stripped_content}"
                modified_sections.append((header, new_content))
            else:
                modified_sections.append((header, content))

        report.sections = modified_sections

上一篇 Spring-AI

下一篇 Python-SQLAlchemy

阅读
评论
1.1k
阅读预计4分钟
创建日期 2025-03-23
修改日期 2025-03-23
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论