Python 单元测试与 pytest 实践

2026-03-06

单元测试(Unit Test)对代码中的最小可测单元(如函数、类方法)进行验证,在修改代码后快速发现回归错误。pytest 是 Python 生态中最主流的测试框架之一,语法简洁、支持 fixture 与参数化、插件丰富。本文介绍 pytest 的安装与基础、用例编写、fixture、参数化、覆盖率及与 CI 的集成,帮助开发者建立可持续的自动化测试体系。

一、单元测试与 pytest 为何重要

根据多项软件工程研究,持续运行单元测试可显著降低线上缺陷率;在重构或加功能时,测试可提供安全网。pytest 在 PyPI 下载量长期位居测试类前列,社区与文档成熟。

能力说明
自动发现默认收集 test_ 开头或 _test 结尾的函数、Test 开头的类
断言使用 assert 即可,失败时自动输出 diff
fixture依赖注入式准备数据与环境
参数化一组用例多组数据,减少重复代码
插件pytest-cov 覆盖率、pytest-xdist 并行等

数据来源:PyPI 下载统计、pytest 官方文档(综合整理)。

二、pytest 安装与基础

安装:pip install pytest pytest-cov。pytest-cov 用于生成覆盖率报告。项目结构建议:源码放 src 或包名目录,测试放 tests/,测试文件以 test_ 开头或 _test 结尾。

2.1 运行测试

pytest:运行当前目录及子目录下所有测试。pytest tests/ -v:只跑 tests 目录,-v 显示详细用例名。pytest tests/test_foo.py -k "test_add":按名称过滤。失败时可用 pytest --pdb 进入调试。

2.2 断言

直接写 assert 表达式即可,例如 assert result == 42assert "error" in str(exc)。pytest 会重写 assert,失败时输出左右值对比。

三、fixture 与参数化

fixture 用于准备测试依赖(如数据库连接、临时文件、mock 对象),通过函数参数注入到用例中。

3.1 定义与使用 fixture

使用 @pytest.fixture 装饰器定义。用例通过同名参数接收,pytest 自动调用 fixture 并注入。scope 可选 function(默认)、class、module、session。

3.2 conftest.py

conftest.py 中的 fixture 无需导入,同目录及子目录下的用例均可使用。常用于定义全局或目录级共享 fixture(如数据库、配置)。

3.3 参数化

@pytest.mark.parametrize("a,b,expected", [(1,2,3), (0,0,0)]):多组输入与期望,减少重复。可与 fixture 组合使用。

用法说明
@pytest.fixture定义可复用资源,支持 scope
@pytest.mark.parametrize多组参数驱动,参数名与用例参数一致
conftest.py共享 fixture,无需 import
pytest.raises(SomeError)断言抛出指定异常

四、覆盖率与 CI 集成

运行 pytest --cov=src --cov-report=html --cov-report=term 可生成终端与 HTML 覆盖率报告。--cov-fail-under=80 可在覆盖率低于 80% 时令 pytest 失败。在 CI 中:每次提交或 PR 触发 pytest,覆盖率低于阈值则阻断合并。可参考本站《CI/CD 与持续交付实践》。

五、测试设计要素权重

基于实际项目经验,单元测试落地时以下要素的影响程度(相对权重,满分 100):

用例覆盖核心逻辑
92%
fixture 与可维护性
85%
覆盖率与 CI 联动
82%
执行速度
75%

说明:权重基于 pytest 项目实践归纳,仅供参考。

六、小结

pytest 通过 fixture 与参数化提升测试复用与可维护性,结合覆盖率与 CI 可实现持续验证。建议从核心业务逻辑开始写测试,逐步提高覆盖率。若需前端 E2E 或端到端测试思路,可阅读《前端性能监控与可观测性》;若需完整自动化流水线,可参考《CI/CD 与持续交付实践》。