【Python】pytest 库:功能强大且广泛使用的开源测试框架
pytest 是 Python 中一个功能强大且广泛使用的测试框架,用于编写和运行单元测试、集成测试以及其他类型的测试。它以简单易用、灵活性和强大的插件生态系统而闻名,适合从小型项目到大型应用的测试需求。相比 Python 内置的 unittest 模块,pytest 提供更简洁的语法、更少的样板代码和丰富的功能。本文将详细介绍 pytest 库,包括其核心功能、用法、常见特性、插件系统以及最佳实
pytest
是 Python 中一个功能强大且广泛使用的测试框架,用于编写和运行单元测试、集成测试以及其他类型的测试。它以简单易用、灵活性和强大的插件生态系统而闻名,适合从小型项目到大型应用的测试需求。相比 Python 内置的 unittest
模块,pytest
提供更简洁的语法、更少的样板代码和丰富的功能。本文将详细介绍 pytest
库,包括其核心功能、用法、常见特性、插件系统以及最佳实践。
1. pytest
简介
pytest
是一个开源的测试框架,支持 Python 2.7 和 3.5 及以上版本。它的设计目标是让测试代码更简洁、易读,同时提供强大的功能,如自动测试发现、丰富的断言、参数化测试和插件扩展。
主要特点
- 简洁的语法:无需继承测试类,普通函数即可作为测试用例。
- 自动测试发现:自动查找和运行符合命名规则的测试文件和函数。
- 强大的断言:使用 Python 的
assert
语句,无需特殊断言方法。 - 参数化测试:支持测试用例的参数化,减少重复代码。
- 插件生态:丰富的插件支持,如覆盖率分析、并行测试等。
- 详细的报告:提供清晰的测试结果和失败信息。
安装
使用 pip
安装 pytest
:
pip install pytest
检查安装:
pytest --version
2. 基本用法
pytest
的使用非常直观,以下是编写和运行测试的基本步骤。
1) 编写测试
pytest
的测试用例是普通的 Python 函数,遵循以下命名约定:
- 测试文件以
test_
开头或以_test
结尾(如test_example.py
)。 - 测试函数以
test_
开头(如test_function
)。 - 测试类以
Test
开头,方法以test_
开头。
示例(test_math.py
):
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
2) 运行测试
在终端中运行:
pytest
pytest
会自动发现当前目录及其子目录中符合命名规则的测试文件并执行。输出类似:
============================= test session starts ==============================
platform linux -- Python 3.10.12, pytest-8.3.2, pluggy-1.5.0
collected 1 item
test_math.py . [100%]
============================== 1 passed in 0.01s ===============================
3) 常用命令行选项
pytest -v
:详细输出,显示每个测试的名称。pytest test_math.py
:运行特定文件。pytest test_math.py::test_add
:运行特定测试函数。pytest -k "add"
:运行包含“add”关键字的测试。pytest --collect-only
:仅收集测试用例,不执行。pytest -x
:在第一个失败时停止。pytest --maxfail=2
:在指定数量的失败后停止。
3. 核心功能
pytest
提供了丰富的功能,以下是核心特性和用法。
1) 断言
pytest
使用 Python 的内置 assert
语句,无需特殊的断言方法。失败时,pytest
会提供详细的错误信息。
示例:
def test_string():
assert "hello".upper() == "HELLO"
assert "hello" + " world" == "hello world"
失败输出:
> assert "hello".upper() == "HELLO!"
E AssertionError: assert 'HELLO' == 'HELLO!'
E - HELLO
E + HELLO!
2) 自动测试发现
pytest
自动查找测试文件和函数:
- 文件:
test_*.py
或*_test.py
。 - 函数:以
test_
开头的函数。 - 类:以
Test
开头的类,其方法以test_
开头。
示例(test_example.py
):
class TestExample:
def test_one(self):
assert 1 + 1 == 2
def test_two(self):
assert 2 * 2 == 4
运行 pytest
会发现并执行 test_one
和 test_two
。
3) 异常测试
使用 pytest.raises
测试代码是否抛出预期异常。
示例:
import pytest
def divide(a, b):
return a / b
def test_divide_by_zero():
with pytest.raises(ZeroDivisionError):
divide(10, 0)
4) 参数化测试
使用 @pytest.mark.parametrize
为测试函数提供多组输入数据,减少重复代码。
示例:
import pytest
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0),
])
def test_add(a, b, expected):
assert add(a, b) == expected
运行后,test_add
会为每组参数运行一次,生成三个测试用例。
5) 夹具(Fixtures)
夹具是 pytest
的核心功能,用于提供测试所需的资源(如数据、对象、临时文件)。夹具通过 @pytest.fixture
装饰器定义。
示例:
import pytest
@pytest.fixture
def sample_data():
return [1, 2, 3]
def test_sum(sample_data):
assert sum(sample_data) == 6
-
夹具作用域:控制夹具的生命周期(如
function
、module
、session
)。@pytest.fixture(scope="module") def db_connection(): conn = create_connection() # 假设的函数 yield conn # 返回资源 conn.close() # 清理
-
自动使用夹具:通过
autouse=True
自动应用夹具。@pytest.fixture(autouse=True) def setup(): print("\nSetup") yield print("Teardown")
6) 标记(Markers)
使用 @pytest.mark
为测试添加标记,用于分类或选择性运行。
示例:
import pytest
@pytest.mark.slow
def test_slow_operation():
assert True
@pytest.mark.unit
def test_unit():
assert 1 + 1 == 2
运行特定标记的测试:
pytest -m slow # 仅运行标记为 slow 的测试
pytest -m "not slow" # 排除 slow 标记的测试
自定义标记需在 pytest.ini
中注册:
[pytest]
markers =
slow: marks tests as slow
unit: marks unit tests
7) 跳过和预期失败
@pytest.mark.skip
:跳过测试。@pytest.mark.skipif
:根据条件跳过。@pytest.mark.xfail
:标记测试预期失败。
示例:
import sys
@pytest.mark.skip(reason="Not implemented yet")
def test_not_ready():
assert False
@pytest.mark.skipif(sys.version_info < (3, 8), reason="Requires Python 3.8+")
def test_new_feature():
assert True
@pytest.mark.xfail
def test_may_fail():
assert False # 失败但不计入失败统计
4. 插件系统
pytest
的插件生态系统非常强大,提供了额外的功能。常用插件包括:
1) pytest-cov
- 用途:测量测试覆盖率。
- 安装:
pip install pytest-cov
- 用法:
生成 HTML 覆盖率报告。pytest --cov=src --cov-report=html
2) pytest-mock
- 用途:简化 mock 对象的使用。
- 安装:
pip install pytest-mock
- 示例:
def test_mock(mocker): mocked = mocker.patch("module.some_function", return_value=42) assert module.some_function() == 42
3) pytest-asyncio
- 用途:支持异步测试。
- 安装:
pip install pytest-asyncio
- 示例:
import pytest import asyncio @pytest.mark.asyncio async def test_async_function(): await asyncio.sleep(0.1) assert True
4) pytest-xdist
- 用途:并行运行测试,加速执行。
- 安装:
pip install pytest-xdist
- 用法:
pytest -n 4 # 使用 4 个进程并行运行
5) 自定义插件
开发者可以编写自定义插件,扩展 pytest
功能。插件通常定义夹具、钩子函数或标记。
示例(pytest_custom.py
):
def pytest_addoption(parser):
parser.addoption("--custom", action="store", default="value")
@pytest.fixture
def custom_option(request):
return request.config.getoption("--custom")
使用:
pytest --custom=hello
5. 配置 pytest
pytest
支持通过配置文件(如 pytest.ini
、pyproject.toml
)定制行为。
示例(pytest.ini
):
[pytest]
python_files = test_*.py
python_functions = test_*
addopts = -v --cov=src --cov-report=html
markers =
slow: slow tests
示例(pyproject.toml
):
[tool.pytest.ini_options]
python_files = "test_*.py"
addopts = "-v"
6. 最佳实践
-
编写简洁的测试:
- 每个测试函数专注于单一职责。
- 使用描述性名称,如
test_add_handles_negative_numbers
。
-
使用夹具管理资源:
- 将初始化和清理逻辑放入夹具,保持测试代码干净。
- 示例:
@pytest.fixture def temp_file(tmp_path): f = tmp_path / "test.txt" f.write_text("hello") return f
-
参数化测试减少重复:
- 使用
@pytest.mark.parametrize
覆盖多种输入场景。 - 示例:
@pytest.mark.parametrize("input, expected", [("a", "A"), ("b", "B")]) def test_upper(input, expected): assert input.upper() == expected
- 使用
-
避免过度依赖 mock:
- 仅在必要时(如测试外部依赖)使用 mock,避免测试过于复杂。
-
定期检查覆盖率:
- 使用
pytest-cov
确保测试覆盖关键代码路径。
- 使用
-
集成到 CI/CD:
- 将
pytest
集成到 GitHub Actions 或 Jenkins,确保每次提交运行测试。 - 示例(GitHub Actions):
name: Run Tests on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.10" - run: pip install pytest pytest-cov - run: pytest --cov=src
- 将
-
处理 flaky 测试:
- 使用
pytest-rerunfailures
重试不稳定的测试:pip install pytest-rerunfailures pytest --reruns 3
- 使用
7. 注意事项
-
测试隔离:
- 确保测试之间独立,避免状态泄漏。
- 使用夹具或
tmp_path
管理临时资源。
-
性能优化:
- 对于大型测试套件,使用
pytest-xdist
并行执行。 - 避免在夹具中执行昂贵操作,设置适当的
scope
。
- 对于大型测试套件,使用
-
版本兼容性:
- 确保
pytest
和插件版本与 Python 版本兼容。 - 检查插件文档,某些功能可能需要特定版本。
- 确保
-
调试失败:
- 使用
pytest --pdb
进入调试器:pytest --pdb
- 查看详细输出:
pytest -vv
.
- 使用
-
避免过度标记:
- 仅为必要分类使用标记,保持配置简单。
8. 总结
pytest
是 Python 生态中最强大的测试框架之一,凭借简洁的语法、自动测试发现、参数化测试、夹具和插件系统,极大地提高了测试开发的效率。核心功能包括:
- 简洁断言:使用
assert
提供详细错误信息。 - 夹具:管理测试资源,支持作用域和自动使用。
- 参数化:通过
@pytest.mark.parametrize
简化多场景测试。 - 插件:如
pytest-cov
、pytest-asyncio
扩展功能。 - 配置:通过
pytest.ini
或pyproject.toml
定制行为。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)