一、什么是 Pytest?
pytest 是 Python 中一个功能强大且广泛使用的测试框架。相比 Python 自带的 unittest,它语法简洁、功能丰富,支持参数化测试、插件扩展、断言简化等特性,极大提升了编写和运行测试的效率
二、安装 Pytest
在命令行中使用 pip 安装
pip install pytest
验证是否安装成功:
pytest --version
三、第一个测试用例
1. 创建测试文件
创建一个名为 test_sample.py 的文件:
# test_sample.pydef add(a, b):return a + bdef test_add():assert add(2, 3) == 5assert add(-1, 1) == 0assert add(0, 0) == 0
2. 运行测试
在终端中执行:
pytest test_sample.py
或简写:
(pytest 会自动发现当前目录下以 test_ 开头或 _test.py 结尾的文件)
输出示例:
============================= test session starts ==============================
collected 1 itemtest_sample.py . [100%]============================== 1 passed in 0.01s ===============================
✅ 表示测试通过。
四、Pytest 基本规则
- 测试文件名以 test_ 开头 或 以 _test.py 结尾。
- 测试函数名必须以 test_ 开头。
- 使用 assert 关键字进行断言,无需导入 unittest.TestCase。
五、常见用法示例
1. 测试异常
使用 pytest.raises 捕获预期异常:
import pytestdef divide(a, b):if b == 0:raise ValueError("Cannot divide by zero")return a / bdef test_divide_by_zero():with pytest.raises(ValueError, match="Cannot divide by zero"):divide(10, 0)
2. 参数化测试(@pytest.mark.parametrize)
避免重复写多个测试用例。
import pytest@pytest.mark.parametrize("a, b, expected", [(2, 3, 5),(-1, 1, 0),(0, 0, 0),(100, -50, 50)
])
def test_add_parametrized(a, b, expected):assert add(a, b) == expected
运行后,每个参数组合都会作为独立测试运行。
3. 跳过测试
@pytest.mark.skip(reason="临时跳过这个测试")
def test_skip_example():assert False
4. 条件跳过
import sys@pytest.mark.skipif(sys.version_info < (3, 8), reason="需要 Python 3.8+")
def test_only_in_new_python():assert True
5. 标记测试(Mark)
可以给测试打标签,方便分组运行。
@pytest.mark.slow
def test_slow_function():import timetime.sleep(2)assert True@pytest.mark.smoke
def test_smoke():assert True
运行特定标记的测试:
pytest -m "smoke" # 只运行 smoke 标记的测试
pytest -m "not slow" # 排除 slow 测试
六、测试夹具(Fixtures)——核心功能
fixture 是 pytest 最强大的功能之一,用于准备测试环境(如数据库连接、临时文件等)。
示例:使用 fixture 提供测试数据
import pytest@pytest.fixture
def sample_data():return [1, 2, 3, 4, 5]def test_sum(sample_data):assert sum(sample_data) == 15def test_length(sample_data):assert len(sample_data) == 5
fixture 作用域(scope)
@pytest.fixture(scope="module")
def db_connection():print("连接数据库")conn = "database_connection"yield connprint("关闭数据库")
- scope="function":每个测试函数前运行(默认)
- scope="module":每个测试文件前运行一次
- scope="session":整个测试会话只运行一次
七、测试组织结构建议
推荐目录结构:
my_project/
│
├── src/
│ └── myapp.py
│
├── tests/
│ ├── test_myapp.py
│ └── test_utils.py
│
└── pytest.ini (可选配置文件)
八、常用命令行选项
命令 | 说明 |
pytest | 运行所有测试 |
pytest test_file.py::test_function | 运行指定函数 |
pytest -v | 显示详细结果 |
pytest -x | 遇到失败立即停止 |
pytest --tb=short | 简化 traceback 输出 |
pytest --collect-only | 仅收集测试,不运行 |
pytest -k "add or divide" | 运行包含 "add" 或 "divide" 的测试 |
pytest --html=report.html | 生成 HTML 报告(需安装pytest-html) |
九、安装常用插件
# 生成 HTML 报告
pip install pytest-html
pytest --html=report.html# 重新运行失败的测试
pip install pytest-rerunfailures
pytest --reruns 3# 输出覆盖率报告
pip install pytest-cov
pytest --cov=src tests/
十、最佳实践建议
✅ 测试函数保持单一职责
✅ 使用 parametrize 减少重复代码
✅ 合理使用 fixture 管理测试依赖
✅ 给测试加清晰的命名,如 test_add_positive_numbers
✅ 避免测试之间相互依赖
✅ 使用 .gitignore 忽略测试报告和缓存文件(如 __pycache__, .pytest_cache)
十一、完整示例项目
src/calculator.py:
def multiply(x, y):return x * y
tests/test_calculator.py:
import pytest
from src.calculator import multiply@pytest.mark.parametrize("x,y,result", [(2, 3, 6),(0, 100, 0),(-1, 5, -5),(1, 1, 1)
])
def test_multiply(x, y, result):assert multiply(x, y) == result
运行:
pytest tests/test_calculator.py -v
十二、参考资料
- 官方文档:https://docs.pytest.org/
- GitHub: https://github.com/pytest-dev/pytest
- 插件仓库:https://plugincompat.herokuapp.com/
🎉 恭喜!你已经掌握了 Pytest 的基本用法。现在可以开始为你的项目编写清晰、高效的自动化测试了!