pytest 测试项目指南

下面是一个完整的 pytest 测试项目结构示例,包含了最佳实践和常见配置:

项目结构

Plain Text

复制代码
project-name/
├── src/                     # 应用程序源代码
│   └── app.py
├── tests/                   # 测试目录
│   ├── unit/                # 单元测试
│   │   ├── test_app.py
│   │   └── test_utils.py
│   ├── integration/         # 集成测试
│   │   └── test_api.py
│   ├── conftest.py          # 共享的fixture和配置
│   └── pytest.ini           # pytest配置文件
├── .gitignore
├── requirements.txt         # 项目依赖
└── setup.py                 # 安装脚本(可选)

关键文件内容

1. src/app.py (示例应用代码)

python

复制代码
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

2. tests/unit/test_app.py (单元测试)

python

复制代码
import pytest
from src.app import add, subtract, multiply, divide

class TestMathOperations:
    def test_add(self):
        assert add(2, 3) == 5
        assert add(-1, 1) == 0
        
    def test_subtract(self):
        assert subtract(5, 3) == 2
        assert subtract(3, 5) == -2
        
    def test_multiply(self):
        assert multiply(3, 4) == 12
        assert multiply(0, 5) == 0
        
    def test_divide(self):
        assert divide(10, 2) == 5
        
    def test_divide_by_zero(self):
        with pytest.raises(ValueError) as exc_info:
            divide(10, 0)
        assert "Cannot divide by zero" in str(exc_info.value)

3. tests/conftest.py (共享fixture)

python

复制代码
import pytest

# 共享fixture示例
@pytest.fixture
def sample_data():
    return {"a": 10, "b": 5}

# 配置pytest钩子
def pytest_addoption(parser):
    parser.addoption("--slow", action="store_true", default=False, 
                     help="Run slow tests")

def pytest_collection_modifyitems(config, items):
    if not config.getoption("--slow"):
        skip_slow = pytest.mark.skip(reason="need --slow option to run")
        for item in items:
            if "slow" in item.keywords:
                item.add_marker(skip_slow)

4. tests/pytest.ini (配置文件)

ini

复制代码
[pytest]
addopts = -v --cov=src --cov-report=html
testpaths = tests/unit tests/integration
markers =
    slow: marks tests as slow (deselect with '-m "not slow"')

5. requirements.txt (依赖文件)

Plain Text

复制代码
pytest==7.1.2
pytest-cov==3.0.0
requests==2.27.1  # 用于API测试

运行测试

基本命令

bash

复制代码
# 运行所有测试
pytest

# 运行特定目录下的测试
pytest tests/unit

# 运行特定文件中的测试
pytest tests/unit/test_app.py

# 运行特定类中的测试
pytest tests/unit/test_app.py::TestMathOperations

# 运行特定测试方法
pytest tests/unit/test_app.py::TestMathOperations::test_add

高级选项

bash

复制代码
# 生成覆盖率报告
pytest --cov=src

# 只运行标记为slow的测试
pytest -m slow

# 跳过标记为slow的测试
pytest -m "not slow"

# 在失败时启动调试器
pytest --pdb

# 并行运行测试(需要pytest-xdist)
pytest -n auto

最佳实践

  1. 命名约定

    • 测试文件:test_*.py*_test.py

    • 测试类:Test*

    • 测试方法:test_*

  2. 测试组织

    • 按功能模块分组测试

    • 将单元测试与集成测试分离

    • 使用标记(markers)分类测试

  3. 使用fixture

    • 避免重复设置代码

    • 创建可重用的测试环境

    • 使用conftest.py共享fixture

  4. 参数化测试

    python

    复制代码
    @pytest.mark.parametrize("a,b,expected", [
        (1, 2, 3),
        (-1, 1, 0),
        (10, 20, 30)
    ])
    def test_add(a, b, expected):
        assert add(a, b) == expected
  5. 测试覆盖率

    • 使用pytest-cov生成覆盖率报告

    • 目标覆盖关键业务逻辑

    • 但不要追求100%覆盖率(可能产生低价值测试)

  6. 持续集成

    • 在CI/CD流程中运行测试

    • 设置测试失败时的警报

    • 使用测试结果作为质量门禁

常见插件

  1. pytest-cov:代码覆盖率报告

  2. pytest-xdist:并行运行测试

  3. pytest-mock:简化mock使用

  4. pytest-django:Django项目支持

  5. pytest-asyncio:异步测试支持

  6. pytest-html:生成HTML报告

调试技巧

  1. 使用pytest --trace在测试开始时启动调试器

  2. 添加print()语句输出调试信息

  3. 使用pytest -s禁用输出捕获(显示print输出)

  4. 在失败测试中使用pdb

    python

    复制代码
    def test_failing():
        result = some_function()
        import pdb; pdb.set_trace()  # 在此设置断点
        assert result == expected

这个结构提供了一个健壮的测试基础,可以根据项目需求进行调整和扩展。

相关推荐
周杰伦fans4 天前
记一次 Visual Studio 突然报错“未能加载 Microsoft.Internal.VisualStudio.Interop”的奇葩经历
microsoft·log4j·visual studio
laplaya4 天前
C++大型项目组件通信与依赖管理实践
c++·log4j·apache
福大大架构师每日一题5 天前
ollama v0.30.7 正式发布:Hermes 桌面端落地,接口、文档、底层依赖全方位优化
golang·log4j
四问四不知6 天前
Understand Anything的初步了解
log4j
wh_xia_jun7 天前
单元测试 + Mockito 开发指南
oracle·单元测试·log4j
kTR2hD1qb8 天前
Privaze源码级避坑指南技术文章大纲
log4j
阿正的梦工坊8 天前
【Rust】10-Cargo、测试与实用开发工作流
java·rust·log4j
捏塔10 天前
完美自动生成单元测试SKILL
单元测试·log4j
AI浩11 天前
指令微调与对齐技术:SFT、RLHF、DPO、RLAIF 与 RLVR(分层式精讲)
log4j
有浔则灵11 天前
从零开始构建 AI Agent(一):理解 Eino 的 Component 抽象与流式对话
人工智能·log4j