AIGC标识 pytest

pytest 的核心体系可以归纳为 6 大支柱

  1. 测试发现与命名约定
    pytest 靠命名规则自动收集测试,无需手动注册:
规则 要求
文件名 test_*.py*_test.py
函数/方法名 test_ 开头
类名 Test 开头(且不能有 __init__
  • 自定义收集规则可在 pyproject.toml 中通过 [tool.pytest.ini_options] 配置。
  1. Fixture(测试夹具)
    这是 pytest 最核心的依赖注入机制:
点击查看代码
@pytest.fixture(scope="session")     # 作用域控制
def db(): ...

@pytest.fixture(autouse=True)        # 自动应用
def mock_env(): ...

@pytest.fixture(params=["mysql", "pg"])  # 参数化 fixture
def database(request): ...

核心要点:

  • 通过参数名匹配自动注入
  • yield 实现 setup + teardown
  • 支持 function / class / module / package / session 五级作用域
  • conftest.py 中的 fixture 对同目录及子目录自动可见
  1. Assert 断言
    pytest 不需要 self.assertEqual() 这类专用断言方法,直接用原生 assert:
点击查看代码
assert result == expected
assert "error" in message
assert isinstance(obj, dict)
assert path.exists()
  • 失败时 pytest 会自动 introspect 左右两边的值并给出详细对比,比 unittest 的断言信息丰富得多。
  1. Mark 标记系统
    用装饰器给测试打标签,实现分类、跳过、参数化等:

采用了 类(Class)+ Fixture 的组织模式。这种写法是企业级 Python 项目中测试的“最佳实践”范式
AAA 结构:Arrange → Act → Assert 三段式是测试的黄金法则,保证每个测试只做一件事、只验证一个行为。
1.

标记 作用 典型场景
@pytest.mark.parametrize 参数化:一个测试函数自动运行多组输入 边界值、多格式、多语言测试
@pytest.mark.skip 无条件跳过 功能未实现、已知 bug 暂不修
@pytest.mark.skipif 条件跳过 特定 OS/Python 版本/缺少依赖时跳过
@pytest.mark.xfail 预期失败 已知 bug 但先记录,修复后自动提醒
@pytest.mark.asyncio 异步测试 让 pytest 用事件循环运行 async def
标记 作用 配合命令
@pytest.mark.integration 自定义:集成测试 pytest -m integration
@pytest.mark.slow 自定义:慢测试 pytest -m "not slow"
@pytest.mark.unit 自定义:单元测试 pytest -m unit
@pytest.mark.timeout(N) 超时保护(需插件) 防止死锁/无限循环
@pytest.mark.order(N) 执行顺序(需插件) 依赖前置条件的测试
标记 作用 注意事项
@pytest.mark.usefixtures 类/模块级批量应用 fixture 当测试函数不需要直接使用 fixture 返回值时用
@pytest.mark.filterwarnings 控制警告行为 忽略第三方库的无害警告
@pytest.mark.tryfirst / trylast 控制 hook/fixture 执行优先级 插件开发或复杂 fixture 依赖时使用
@pytest.mark.no_cover 排除覆盖率统计(需插件) 纯装饰性代码、调试辅助函数

例如:
@pytest.mark.integration = 给测试贴一个"我是集成测试"的标签
[tool.pytest.ini_options]
markers = [
"integration: 需要外部服务的集成测试",
"slow: 运行时间较长的测试",
"unit: 纯单元测试",
]

需要标记测试?
├── 多组输入 → parametrize
├── 不想跑 → skip / skipif
├── 知道会挂 → xfail
├── 异步代码 → asyncio
├── 分类管理 → 自定义 (integration/slow/unit)
├── 防卡死 → timeout
└── 批量注入依赖 → usefixtures

pytest -m "integration" # 只跑集成测试
pytest -m "not slow" # 跳过慢测试
pytest -m "unit and not slow" # 快速的单元测试
pytest -m "integration or e2e" # 集成或端到端
pytest --strict-markers # CI 中推荐:未注册的标记直接报错

  1. 内置 Fixture
    pytest 自带一批开箱即用的 fixture,无需定义:
Fixture 用途
tmp_path / tmp_path_factory 临时目录(自动清理)
capsys / capfd 捕获 stdout/stderr
monkeypatch 安全地修改环境变量、属性、字典
request 获取当前测试的元信息(参数、mark、nodeid)
recwarn 捕获警告
cache 跨测试运行的持久化缓存
  1. 插件生态
    pytest 的强大很大程度上来自插件,以下是事实标准级别的:
插件 作用
pytest-cov 覆盖率报告
pytest-mock mocker fixture,替代 unittest.mock
pytest-xdist 多进程并行执行测试
pytest-asyncio 异步测试支持
pytest-html HTML 测试报告
pytest-random-order 随机执行顺序,发现隐式依赖
pytest-benchmark 性能基准测试

安装后零配置即可使用(大部分通过 entry point 自动注册)。

知识优先级建议
如果你正在学习 pytest,建议按以下顺序掌握:
assert + 命名约定 → 能写最基本的测试
fixture + yield → 解决 setup/teardown 和资源管理
parametrize → 消除重复测试代码
内置 fixture(tmp_path, monkeypatch, capsys)→ 避免造轮子
mark + 命令行筛选(-k, -m)→ 灵活控制测试运行
插件 → 按需引入,不要一开始就装一堆

  • 运行测试的常用命令
点击查看代码
uv run pytest                          # 跑所有
uv run pytest -v                       # 详细输出(每个测试一行)
uv run pytest -x                       # 第一个失败就停
uv run pytest -k "run_sql"             # 只跑名字含 run_sql 的
uv run pytest src/test/test_run_sql.py # 只跑这个文件
uv run pytest src/test/test_run_sql.py::test_run_sql_rejects_non_select  # 只跑这一个
uv run pytest --lf                     # 只跑上次失败的
uv run pytest -s                       # 显示 print 输出
uv run pytest --cov=mssql_mcp          # 覆盖率(需要 pytest-cov)
posted @ 2026-08-03 11:47  不知者buwei  阅读(0)  评论(0)    收藏  举报