news 2026/10/7 15:21:44

pytest 入门与实践:从第一个测试到可维护的测试体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
pytest 入门与实践:从第一个测试到可维护的测试体系

pytest 入门与实践:从第一个测试到可维护的测试体系

面向 Python 开发者与测试工程师的实战指南,涵盖安装、发现规则、断言、fixture、参数化、标记、配置、常用命令和团队实践。

阅读对象:刚开始写 Python 自动化测试的开发者、测试工程师,以及希望改进测试项目的团队。
预计阅读:约 5 分钟 ·示例环境:Python 3.10+、pytest
https://github.com/lfl171/pytest_zhishi.git

目录

  1. pytest 是什么
  2. 安装与第一个测试
  3. 测试发现与命名
  4. assert 与失败信息
  5. Fixture:组织前置条件和清理
  6. 参数化
  7. Marker:给测试分类与筛选
  8. 常用内置能力
  9. 配置与命令行
  10. 推荐项目结构与实践
  11. 常见问题
  12. 小结

1. pytest 是什么

pytest 是 Python 生态中广泛使用的测试框架。它适用于从小型单元测试到集成测试的多种场景,也能运行许多基于unittest的现有测试。主要特点如下:

  • 低门槛:普通函数配合 Python 原生assert即可编写测试,无需继承特定测试基类。
  • 清晰的失败诊断:断言失败时展示表达式中的实际值,便于定位问题。
  • Fixture 机制:复用依赖与资源准备,并管理生命周期和清理。
  • 参数化与标记:扩展输入组合,并按类别选择测试。
  • 插件生态:接入覆盖率、并行执行、浏览器自动化等能力。

pytest 是测试运行与组织工具,不会自动判断产品需求是否覆盖充分。测试质量仍取决于清晰的预期、有效的边界分析和可靠的测试数据。

2. 安装与第一个测试

推荐在项目虚拟环境中安装,避免依赖污染系统 Python:

python-mvenv .venv# Windows PowerShell.venv\Scripts\Activate.ps1# macOS / Linux: source .venv/bin/activatepython-mpipinstallpytest

创建test_calculator.py:

defadd(a:int,b:int)->int:returna+bdeftest_add_two_positive_numbers():assertadd(2,3)==5

在项目根目录运行:

python-mpytest

成功时通常会看到1 passed。使用python -m pytest可明确通过当前 Python 环境执行模块;也可以直接运行pytest。

3. 测试发现与命名

默认情况下,pytest 会递归发现符合约定的测试文件、类和函数:

  • 文件名通常是test_*.py或*_test.py。
  • 函数名以test_开头。
  • 测试类以Test开头,且通常不定义__init__。
  • 类中的测试方法以test_开头。

明确且一致的命名让收集行为可预测。可用pytest --collect-only先检查将运行哪些测试;只运行某个文件、类或函数时,可用节点路径:

pytest --collect-only pytest tests/test_user.py pytest tests/test_user.py::TestUser::test_create_user

测试函数名宜描述行为和场景,例如test_rejects_expired_token,而不是test_case_03。若项目采用src/布局,建议将产品代码作为已安装包导入,并在项目配置中设置测试路径,减少因当前工作目录不同导致的导入差异。

4. assert 与失败信息

直接使用 Python 的assert表达预期:

deftest_discounted_price():price=100discount=0.2final_price=price*(1-discount)assertfinal_price==80assertfinal_price<price

失败时 pytest 会重写断言表达式,展示参与比较的值。测试应验证对使用者有意义的行为,而非重复实现被测函数的内部算法。对浮点数,优先使用容差比较:

assertactual==pytest.approx(0.3)

5. Fixture:组织前置条件和清理

Fixture 是 pytest 的依赖准备机制。测试函数把 fixture 名称写作参数,pytest 会找到对应 fixture 并注入其返回值。Fixture 可以依赖其他 fixture,形成可组合的准备流程。

importpytest@pytest.fixturedefuser_record():return{"id":7,"name":"Lin","active":True}deftest_user_is_active(user_record):assertuser_record["active"]isTrue

Fixture 的作用范围

scope控制同一 fixture 实例复用的生命周期:

scope生命周期常见用途
function(默认)每个测试函数隔离性强的临时数据
class一个测试类类内共享且安全的状态
module一个测试模块模块级昂贵准备
package一个包包内共享资源
session整次 pytest 会话只读客户端、公共静态资源

作用范围越大,创建次数越少,但共享状态和测试耦合的风险越高。只有资源允许安全共享时才扩大范围。

使用 yield 清理资源

yield前准备资源,yield后释放。即使测试断言失败,pytest 也会执行已到达的清理部分:

@pytest.fixturedeftemp_connection():connection=open_connection()yieldconnection connection.close()

对于多步资源初始化,应让每一步初始化后就有对应清理保障,避免后续步骤失败时留下半初始化资源。Fixture 应保持职责清晰;避免构造执行大量隐式动作的“万能 fixture”。

在conftest.py中定义的 fixture 可被其目录及子目录中的测试发现,不需要显式导入。建议把共享 fixture 放在合理的目录层级,避免顶层conftest.py成为难以理解的全局依赖集合。

6. 参数化:用一份测试覆盖多组数据

当测试逻辑一致、输入不同时,可用@pytest.mark.parametrize:

importpytest@pytest.mark.parametrize("text, expected",[("hello",5),("",0),("你好",2),],)deftest_character_count(text,expected):assertlen(text)==expected

每组参数会作为独立用例报告,失败时能直接看到是哪组数据出错。对边界、非法输入、等价类尤其有用。给参数命名,避免把所有组合塞进一个测试函数;组合数量过多时,按风险优先级取舍,防止套件膨胀。也可参数化 fixture,或者为单条参数指定pytest.param(..., marks=...)。

7. Marker:给测试分类与筛选

内置 marker 可表达常见执行条件:

importpytest@pytest.mark.skip(reason="功能尚未支持")deftest_future_feature():...@pytest.mark.skipif(notis_windows(),reason="仅 Windows 支持")deftest_windows_behavior():...@pytest.mark.xfail(reason="上游缺陷尚未修复")deftest_known_bug():...

项目也可以定义自有标记(例如slow、integration),然后按标记筛选:pytest -m "not slow"。自定义标记应在配置文件中注册,便于团队理解其意图并避免拼写错误。

标记是分类和选择机制,不应把长期失败测试无限期xfail或skip掩盖起来。标注原因,定期清理过期标记。

8. 常用内置能力

预期异常

用pytest.raises验证异常类型;必要时进一步检查异常消息:

deftest_invalid_age_is_rejected():withpytest.raises(ValueError,match="age must be positive"):create_profile(age=0)

将操作放在with内部的最小范围,避免其它代码意外触发同一个异常,造成误通过。

临时文件与目录

tmp_pathfixture 为每个测试提供独立临时目录:

deftest_export_writes_json(tmp_path):output=tmp_path/"report.json"export_report(output)assertoutput.exists()assert'"status": "ok"'inoutput.read_text(encoding="utf-8")

测试不必在仓库中创建、维护和清理临时文件。

Monkeypatch

内置monkeypatchfixture 可在测试期间临时替换属性、字典项、环境变量或工作目录,并在测试结束后恢复:

deftest_reads_api_key_from_environment(monkeypatch):monkeypatch.setenv("API_KEY","test-key")assertload_api_key()=="test-key"

优先替换系统边界(时间、网络、环境变量、文件系统入口),避免过度模拟内部细节。

9. 配置与命令行

pytest 支持pyproject.toml、pytest.ini、tox.ini等配置形式。新项目可把相关设置集中在pyproject.toml:

[tool.pytest.ini_options] testpaths = ["tests"] addopts = "-ra" markers = [ "slow: 运行时间较长的测试", "integration: 需要外部服务或多个组件的测试", ]

常用命令:

命令用途
pytest运行发现到的测试
pytest -q简洁输出
pytest -v显示每个用例名称
pytest -x第一次失败后停止
pytest --maxfail=2最多遇到指定失败数后停止
pytest -k "user and not slow"按名称表达式筛选
pytest -m integration按 marker 筛选
pytest --collect-only只收集,不执行
pytest --durations=10显示最慢的若干用例
pytest --tb=short使用较短的回溯信息

参数可以组合,例如pytest -q -m "not slow"。CI 中建议保留清晰的失败信息;-x适合快速反馈,不一定适合作为唯一的完整回归运行方式。

10. 推荐项目结构与实践

my_project/ ├── pyproject.toml ├── src/ │ └── my_project/ │ └── calculator.py └── tests/ ├── conftest.py ├── unit/ │ └── test_calculator.py └── integration/ └── test_api.py

实用原则:

  1. 先测可观察行为:输入、输出、状态变化和错误处理比私有实现细节稳定。
  2. 每个测试可独立运行:避免依赖执行顺序或共享可变数据。
  3. 失败要可诊断:测试名描述场景,断言定位明确,测试数据具有代表性。
  4. 管理外部依赖:将网络、数据库、时间等边界隔离;集成测试使用可控环境。
  5. 合理分层:快速单元测试、较慢集成测试分开组织,并按需要选择运行集合。
  6. 把运行方式自动化:在持续集成中安装项目依赖并运行测试,失败时保留日志。
  7. 插件按需添加:插件能扩展能力,也会带来依赖和维护成本;选择有明确价值的插件。

11. 常见问题

为什么没有发现测试?

检查文件名、函数名是否符合约定,确认运行目录和配置中的testpaths,然后执行pytest --collect-only -q查看收集结果。

为什么本地能导入,CI 却报模块找不到?

常见原因是本地工作目录或PYTHONPATH偶然提供了导入路径。将项目按规范安装到虚拟环境,统一 CI 工作目录和安装步骤,并检查src/布局及配置。

为什么测试之间互相影响?

通常是共享可变状态、数据库记录未清理、临时文件重名、环境变量未恢复,或测试依赖运行顺序。使用 function-scope fixture、独立数据标识和可靠清理来修复根因。

单元测试还是端到端测试?

两者解决的问题不同。单元测试反馈快、定位明确;集成或端到端测试验证更多真实组件的协作,但运行成本和环境复杂度更高。应按风险分层组合,而不是期待一种测试覆盖全部风险。

12. 小结

pytest 从简单的assert起步,借助 Fixture 复用准备逻辑,使用参数化覆盖输入空间,再用标记和配置组织不同运行集合。框架提供结构与反馈,可靠的测试仍来自独立、明确、贴近用户行为的验证。

官方资料

  • pytest 官方文档:Get Started
  • pytest 官方文档:Fixtures
  • pytest 官方文档:参数化
  • pytest 官方文档:命令行用法
  • pytest 官方文档:配置选项
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 15:20:44

W9-3495X游戏云实测:MC服务器TPS稳定与配置选择指南

1. 为什么W9-3495X这颗U在MC圈子里突然火了先说说我自己的经历。去年帮朋友开的一个生存服&#xff0c;最开始用的是某平台的常规游戏云&#xff0c;配置写着"4核8G"&#xff0c;结果一上人就开始卡&#xff0c;TPS从20掉到12&#xff0c;红石机器一开直接变幻灯片。…

作者头像 李华
网站建设 2026/10/7 15:18:46

pstack运行时取证与追踪取证:诊断内存泄漏与CPU空转

pstack运行时取证与追踪取证&#xff1a;诊断内存泄漏与CPU空转 【免费下载链接】pstack-claude Claude Code, Codex, Copilot, Pi, OpenCode, Gemini, and Prime Agent versions of Potetos pstack. Rigorous agent workflows with Cursor primitives translated for other ha…

作者头像 李华
网站建设 2026/10/7 15:17:40

从零搭建夏普全系列维修手册:故障排查思路与备件替代实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 15:17:11

IT爱学堂-黑马程序员Python+AI大模型零基础到项目实战,涵盖Python、Linux、LangChain、Ollama等,从大模型私有化部署到搭建聊天机器人一套通关

LoRA 和 QLoRA 到底在学什么——微调入门的核心认知拆解 核心观点&#xff1a;微调入门的真正门槛不是“会不会跑训练脚本”&#xff0c;而是理解LoRA为什么能用1%的参数达到接近全量微调的效果&#xff0c;以及QLoRA如何在LoRA基础上把显存需求再压缩。理解了这个“为什么”&a…

作者头像 李华
网站建设 2026/10/7 15:16:43

参考文献手动整理到崩溃?科迅捷AI一键搞定GB/T 7714格式

写论文最磨人的小事是什么&#xff1f;不是写正文&#xff0c;是整理参考文献。几十上百篇文献&#xff0c;每一条都要按GB/T 7714格式来&#xff1a;期刊文章怎么写、专著怎么写、学位论文怎么写、网页文献怎么写&#xff0c;手动一条一条调格式&#xff0c;调完抬头一看&…

作者头像 李华