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
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: