专栏 :Python 自动化测试从入门到实战|第 1 篇
适读人群 :零基础的测试新手 / Python 开发者
环境要求 :Python ≥ 3.10,pytest ≥ 8.0(推荐 9.x)
预计阅读:10 分钟
前言
本文将带你完成三件事:
- ✅ 搞清楚 pytest 版本与 Python 的兼容关系
- ✅ 在虚拟环境中正确安装 pytest
- ✅ 写出并运行你的第一个测试用例
全程图文并茂,跟着做就能跑通。
一、为什么选 pytest?
Python 自带 unittest,为什么还要学 pytest?一句话:pytest 用更少的代码,做更多的事。
| 对比维度 | unittest | pytest |
|---|---|---|
| 测试定义 | 必须写测试类 | 函数即可 |
| 断言方式 | self.assertEqual(a, b) |
原生 assert |
| 前置后置 | setUp/tearDown |
Fixture(更灵活) |
| 参数化 | 需 subTest 或 ddt |
内置 @pytest.mark.parametrize |
| 插件生态 | 有限 | 极其丰富 |
💡 结论:pytest 是当前 Python 测试的事实标准,社区活跃、文档完善,本专栏全程基于 pytest。
二、版本兼容矩阵(重要!)
安装前务必 确认版本对应关系,否则容易出现 ImportError 或语法不兼容。
| pytest 版本 | 发布时间 | 支持的 Python 版本 | 说明 |
|---|---|---|---|
| 9.x | 2025 ~ | 3.10, 3.11, 3.12, 3.13 | 当前主线,推荐 ✅ |
| 8.x | 2024 | 3.8 ~ 3.12 | 广泛使用,稳定 |
| 7.x | 2022~2023 | 3.7 ~ 3.11 | 老项目常见 |
| ≤ 6.x | 已停止维护 | --- | 不建议新项目使用 |
⚠️ 注意:
- pytest 9.0+ 已放弃对 Python 3.8/3.9 的支持。
- 本文以 Python 3.11 + pytest 9.x 为例,截图与输出均基于此环境。
- 如你在维护老项目,请锁定
pytest==7.4.4。
查看你当前的 Python 版本
打开终端,执行:
bash
python3 --version
# 或 Windows
python --version
输出示例:
text
Python 3.11.9
三、安装前的准备:虚拟环境
🚨 强烈建议 :永远在虚拟环境中安装 pytest,不要污染全局 Python。
方式 A:使用 venv(推荐,标准库自带)
bash
# 1. 创建项目目录
mkdir pytest-demo && cd pytest-demo
# 2. 创建虚拟环境
python3 -m venv .venv
# 3. 激活虚拟环境
# macOS / Linux:
source .venv/bin/activate
# Windows:
.venv\Scripts\activate
# 4. 确认解释器路径
which python # macOS/Linux
where python # Windows
激活成功后,终端提示符前会出现 (.venv):
text
(.venv) ~/pytest-demo $
方式 B:使用 Conda
bash
conda create -n pytest-demo python=3.11 -y
conda activate pytest-demo
四、安装 pytest
虚拟环境就绪后,安装只需一条命令:
bash
pip install pytest
指定具体版本
bash
# 安装最新稳定版
pip install pytest
# 锁定某个版本
pip install pytest==9.0.2
# 升级到最新
pip install --upgrade pytest
验证安装是否成功
bash
pytest --version
期望输出(版本号可能略有差异):
text
pytest 9.0.2
✅ 看到版本号,说明安装成功!
五、你的第一个测试用例
Step 1:创建项目结构
推荐采用如下目录结构(也是 pytest 官方推荐):
text
pytest-demo/
├── .venv/ # 虚拟环境(不入库)
├── src/
│ ├── __init__.py
│ └── calculator.py # 被测试的业务代码
└── tests/
├── __init__.py
└── test_calculator.py # 测试代码
📌 命名规则先记住两条:
- 测试文件必须以
test_开头(或_test.py结尾)- 测试函数必须以
test_开头
Step 2:编写业务代码
src/calculator.py:
python
"""一个简单的计算器模块"""
def add(a: float, b: float) -> float:
"""两数相加"""
return a + b
def subtract(a: float, b: float) -> float:
"""两数相减"""
return a - b
def multiply(a: float, b: float) -> float:
"""两数相乘"""
return a * b
def divide(a: float, b: float) -> float:
"""两数相除,除零抛异常"""
if b == 0:
raise ValueError("除数不能为零")
return a / b
Step 3:编写测试代码
tests/test_calculator.py:
python
from src.calculator import add, subtract, multiply, divide
import pytest
class TestAdd:
"""加法测试"""
def test_add_positive(self):
assert add(1, 2) == 3
def test_add_negative(self):
assert add(-1, -2) == -3
def test_add_zero(self):
assert add(0, 0) == 0
def test_subtract():
assert subtract(5, 3) == 2
def test_multiply():
assert multiply(3, 4) == 12
def test_divide():
assert divide(6, 3) == 2
def test_divide_by_zero():
"""除零应抛出 ValueError"""
with pytest.raises(ValueError, match="除数不能为零"):
divide(1, 0)
Step 4:运行测试
在项目根目录执行:
bash
pytest
你将看到类似输出:
text
================ test session starts =================
platform darwin -- Python 3.11.9, pytest-9.0.2
rootdir: /Users/you/pytest-demo
collected 6 items
tests/test_calculator.py ...... [100%]
================= 6 passed in 0.03s ==================
🎉 六个点
......代表 6 个测试全部通过!恭喜,你的第一个 pytest 测试跑通了!
六、测试发现规则(Test Discovery)
pytest 是如何自动找到这些测试的?记住它的默认发现规则:
| 项目 | 规则 |
|---|---|
| 测试文件 | test_*.py 或 *_test.py |
| 测试类 | 以 Test 开头,且无 __init__ |
| 测试函数/方法 | 以 test_ 开头 |
text
pytest 扫描流程:
当前目录
└── 递归查找 test_*.py / *_test.py
└── 在其中找 test_* 函数
└── 在 Test* 类中找 test_* 方法
自定义规则
如果项目有特殊命名,可在 pytest.ini 中配置:
ini
[pytest]
testpaths = ["tests"]
python_files = test_*.py
python_classes = Test*
python_functions = test_*
七、故意让它失败:看懂断言详情
pytest 的一大亮点:断言失败时自动展示上下文。我们来演示一下。
临时把 test_add_positive 改成错误预期:
python
def test_add_positive(self):
assert add(1, 2) == 4 # 故意写错,应为 3
再次运行:
bash
pytest tests/test_calculator.py::TestAdd::test_add_positive -v
输出:
text
___________________ TestAdd.test_add_positive ____________________
def test_add_positive(self):
> assert add(1, 2) == 4
E assert 3 == 4
E + where 3 = add(1, 2)
tests/test_calculator.py:8: AssertionError
=============== short test summary info ===============
FAILED tests/test_calculator.py::TestAdd::test_add_positive
=========== 1 failed, 5 passed in 0.05s ============
🔍 看关键点:
assert 3 == 4,pytest 清楚告诉你实际值是 3,期望是 4,定位问题一目了然。
记得把代码改回正确值后再继续。
八、常用命令行参数速查
| 命令 | 作用 |
|---|---|
pytest |
运行当前目录所有测试 |
pytest tests/ |
运行指定目录 |
pytest test_x.py |
运行指定文件 |
pytest -v |
详细模式,显示每个用例 |
pytest -q |
简洁模式 |
pytest -k "add" |
按名称关键字匹配 |
pytest -m smoke |
运行带 @pytest.mark.smoke 的用例 |
pytest -x |
遇到第一个失败即停止 |
pytest --maxfail=3 |
失败 3 次后停止 |
pytest -s |
允许打印 print 输出 |
pytest --tb=short |
简化错误追踪 |
pytest --cov=src |
统计覆盖率(需 pytest-cov) |
💡 调试技巧 :用例失败时想看
-s;想定位快,用-x -v。
九、完整运行效果示例
以下是一份「全部通过」的标准输出参考:
text
$ pytest -v
================ test session starts =================
platform darwin -- Python 3.11.9, pytest-9.0.2
rootdir: /Users/you/pytest-demo
collected 6 items
tests/test_calculator.py::TestAdd::test_add_positive PASSED [ 16%]
tests/test_calculator.py::TestAdd::test_add_negative PASSED [ 33%]
tests/test_calculator.py::TestAdd::test_add_zero PASSED [ 50%]
tests/test_calculator.py::test_subtract PASSED [ 66%]
tests/test_calculator.py::test_multiply PASSED [ 83%]
tests/test_calculator.py::test_divide PASSED [100%]
================= 6 passed in 0.03s ==================
看到 PASSED 和末尾的 6 passed,说明一切正常。
十、常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
pytest: command not found |
未激活虚拟环境 / 未安装 | 激活 .venv 后重装 |
ImportError: cannot import name 'add' |
模块路径问题 | 确认 src/ 有 __init__.py,或用 pip install -e . |
collected 0 items |
命名不符合规则 | 文件/函数需以 test_ 开头 |
| 版本警告 | Python 版本过低 | 升级到 3.10+,或降级 pytest |
| 测试相互干扰 | 用例间共享状态 | 使用 fixture,保证隔离 |
十一、小结
通过本文,你已经掌握了:
- ✅ pytest 版本与 Python 的兼容关系
- ✅ 在虚拟环境中正确安装 pytest
- ✅ 项目目录结构与命名规则
- ✅ 编写并运行第一个测试用例
- ✅ 读懂 pytest 的断言失败信息
- ✅ 常用命令行参数
至此,你的本地测试环境已就绪,可以开始系统性地编写测试了。
十二、下一篇预告
👉 《pytest 断言详解与 Fixture 入门》
你将学到:
- pytest 断言的进阶用法(
assert魔法原理) - Fixture 是什么、为什么是 pytest 的灵魂
- 如何用 Fixture 优雅地管理测试前置后置
思考题(欢迎评论区讨论)
- 你的项目里,测试代码和生产代码是分目录存放还是混放?为什么?
- 为什么 pytest 推荐用原生
assert而不是封装好的断言方法? - 试着给
calculator.py再加一个power(a, b)幂运算函数,并写出对应测试。
附录:推荐 .gitignore
gitignore
# 虚拟环境
.venv/
venv/
# Python 缓存
__pycache__/
*.pyc
# 测试产物
.pytest_cache/
*.log
htmlcov/
.coverage
📝 版权声明:本文为作者原创,转载请联系授权。发现错误?欢迎在评论区指正。