查看: 442|回复: 3

Python pytest测试框架从安装到高级用法:Fixture、参数化、钩子函数与并行测试

[复制链接]
发表于 昨天 12:00 | 显示全部楼层 |阅读模式
pytest 是 Python 生态中最灵活且功能丰富的测试框架之一,支持从简单单元测试到复杂集成测试的各类场景。本文将从安装配置讲起,逐步深入到 Fixture 机制、参数化、标记系统、钩子函数以及常用插件(如并行测试、失败重试、覆盖率),帮助你在实际项目中高效使用 pytest。
  1. # 安装 pytest 及常用插件
  2. pip install pytest pytest-html pytest-xdist pytest-rerunfailures pytest-cov
复制代码

推荐的项目结构:将源代码放在 src/,测试放在 tests/,并在根目录放置 pytest.ini 配置文件。
  1. project_root/
  2. ├── src/
  3. │   └── your_module.py
  4. ├── tests/
  5. │   ├── conftest.py
  6. │   ├── test_module_a.py
  7. │   └── subpackage/
  8. │       └── test_sub.py
  9. ├── pytest.ini
  10. └── requirements.txt
复制代码

pytest 自动发现测试遵循命名规则:测试文件名以 test_ 开头或 _test 结尾,测试类以 Test 开头且不含 __init__,测试函数以 test_ 开头。
  1. # test_sample.py
  2. def test_addition():
  3.     assert 1 + 2 == 3
  4. class TestMathOperations:
  5.     def test_multiplication(self):
  6.         assert 3 * 4 == 12
复制代码

运行测试时通过 pytest 命令指定路径或使用 -k 模糊匹配、-m 按标记选择、-v 详细输出、-x 首次失败停止、--lf 只跑上次失败的用例等。可通过 pytest.ini 配置默认选项:
  1. [pytest]
  2. testpaths = tests
  3. python_files = test_*.py
  4. python_classes = Test*
  5. python_functions = test_*
  6. addopts = -v -s --strict-markers
  7. markers =
  8.     slow: marks tests as slow (deselect with '-m "not slow"')
  9.     integration: marks tests as integration tests
  10. log_cli = true
  11. log_cli_level = INFO
复制代码

pytest 返回退出码:0 全通过,1 有失败,2 中断,3 内部错误,4 参数错误,5 未收集到用例。断言直接使用 Python 原生 assert,失败时提供详细上下文。支持异常断言(pytest.raises)和浮点近似(pytest.approx)。
  1. def test_complex_assertions():
  2.     assert "hello" == "hello"
  3.     assert 5 > 3
  4.     assert "lo" in "hello"
  5.     import pytest
  6.     with pytest.raises(ValueError, match="invalid literal"):
  7.         int("not_a_number")
  8.     assert 0.1 + 0.2 == pytest.approx(0.3)
复制代码

生成报告:--junitxml=report.xml 用于 CI/CD,--html=report.html 需安装 pytest-html,--cov=src 需安装 pytest-cov 生成覆盖率报告。

Fixture 是 pytest 最强大的特性之一。使用 @pytest.fixture 定义可重用的上下文,通过参数注入到测试函数。支持 yield 实现 setup/teardown:
  1. @pytest.fixture
  2. def sample_data():
  3.     return {"name": "Alice", "age": 30}
  4. def test_user_age(sample_data):
  5.     assert sample_data["age"] == 30
  6. @pytest.fixture
  7. def database_connection():
  8.     print("建立数据库连接...")
  9.     conn = {"connected": True, "db": "test_db"}
  10.     yield conn
  11.     print("关闭数据库连接...")
  12.     conn["connected"] = False
复制代码

Fixture 作用域(scope)默认为 function,还可设为 class、module、package、session 以减少重复初始化。参数化 fixtrue 通过 params 和 request.param 为不同测试提供不同数据。设置 autouse=True 自动应用于所有测试。

conftest.py 中定义的 fixtrue 可被同一目录下所有测试共享,pytest 自动发现。

参数化测试使用 @pytest.mark.parametrize 装饰器,可组合多个装饰器产生笛卡尔积,并为用例添加描述性 ID:
  1. @pytest.mark.parametrize("input_val, expected", [
  2.     pytest.param(1, 2, id="正整数"),
  3.     pytest.param(0, 0, id="零"),
  4. ])
  5. def test_double(input_val, expected):
  6.     assert input_val * 2 == expected
复制代码

标记系统包括内置标记(skip、skipif、xfail、parametrize、usefixtures)和自定义标记(需在 pytest.ini 中注册)。可用 -m 选择或排除测试,例如 pytest -m "not slow"。
  1. @pytest.mark.slow
  2. def test_slow_operation():
  3.     import time; time.sleep(2)
  4.     assert True
  5. @pytest.mark.skipif(sys.platform != "linux", reason="仅 Linux")
  6. def test_linux_specific():
  7.     assert True
复制代码

钩子函数(Hooks)允许在 conftest.py 中自定义 pytest 行为:pytest_configure 添加自定义标记,pytest_collection_modifyitems 重新排序或添加标记,pytest_runtest_makereport 记录失败信息等。

常用插件:
- 并行测试:pytest-xdist,pytest -n auto 使用所有 CPU 核心,--dist=loadscope 按模块分发。
- 失败重试:pytest-rerunfailures,pytest --reruns 3 --reruns-delay 2,或使用 @pytest.mark.flaky。
- 覆盖率:pytest-cov,pytest --cov=src --cov-report=html --cov-report=term-missing --cov-fail-under=80。
- 测试排序:pytest-order,通过 @pytest.mark.order(1) 指定顺序。

pytest 直接兼容 unittest 风格的测试类,可混合运行。

最佳实践:保持测试独立,使用有意义的名称,每个测试只验证一个逻辑概念,合理使用 fixtrue 和 conftest.py,测试正反边界情况。常见问题:测试发现失败时检查命名规则,通过 --collect-only 调试;fixtrue 意外共享时调整 scope 或返回深拷贝;外部依赖使用 unittest.mock 打桩;测试顺序依赖时用 pytest-randomly 随机化以便发现隐藏依赖。

性能优化建议:使用 -n 并行执行,减少 fixtrue 作用域,避免在 fixtrue 中执行耗时操作,使用 pytest-cov 的 --cov-fail-under 确保覆盖率达标。pytest 的灵活性和插件生态使其成为 Python 测试的首选框架,掌握上述技巧能显著提升测试效率与可靠性。
回复

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python pytest测试框架从安装到高级用法:Fixture、参数化、钩子函数与并行测试

感谢分享,写得非常详细清晰!最近正好在把项目从unittest迁移到pytest,这篇从安装到高级用法的讲解帮了大忙。特别是 fixture 的参数化和作用域设置,之前经常因为重复创建对象导致测试很慢,看了 scope 的设置感觉能优化很多。还有参数化的 id 命名,以前没注意,加中文描述确实能让报告更易读。 对了,关于钩子函数和并发测试那部分,楼主有没有实际项目中的配置示例?比如用 pytest-xdist 时怎么避免 fixture 冲突,或者自定义钩子来做一些全局的前置处理?很想听听实战中的经验。
回复 支持 反对

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python pytest测试框架从安装到高级用法:Fixture、参数化、钩子函数与并行测试

楼主写得很清晰,特别是 fixture 的 yield 实现 setup/teardown 和 conftest 共享部分,非常实用。我想请教一下,在使用 pytest-xdist 进行并行测试时,fixture 的作用域(比如 session 或 module)会不会出现问题?需要额外配置什么才能保证数据隔离或连接池的正确关闭吗?
回复 支持 反对

使用道具 举报

发表于 昨天 12:10 | 显示全部楼层

Re: Python pytest测试框架从安装到高级用法:Fixture、参数化、钩子函数与并行测试

你分享的 pytest 教程很全面,从安装配置到高级特性如 Fixture 和参数化都覆盖了,结构清晰,示例代码也很有参考价值。特别是关于 conftest.py 共享 Fixture 和自定义标记的部分,对实际项目组织很有帮助。另外,你提到的退出码和报告生成对集成 CI/CD 也很实用。感谢分享!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-4 01:26 , Processed in 0.031544 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部