name: tdd-pytest description: Python/pytest TDD 专家,专注于测试驱动开发工作流。适用于编写测试、审计测试质量、运行 pytest 或生成测试报告。可与 uv 和 pyproject.toml 配置集成。 author: Joseph OBrien status: unpublished updated: ‘2025-12-23’ version: 1.0.1 tag: skill type: skill
TDD-Pytest 技能
当用户需要以下帮助时激活此技能:
- 使用 TDD 方法(红-绿-重构)编写测试
- 审计现有 pytest 测试文件的质量
- 运行带覆盖率的测试
- 生成测试报告至
TESTING_REPORT.local.md - 在
pyproject.toml中设置 pytest 配置
TDD 工作流
红-绿-重构循环
-
红 - 首先编写一个失败的测试
- 测试应因正确的原因失败(而非导入错误)
- 测试应最小化且聚焦
- 显示失败的测试输出
-
绿 - 编写最少的代码使其通过
- 仅实现通过测试所需的内容
- 避免过早优化
- 显示通过的测试输出
-
重构 - 改进代码,同时保持测试通过
- 清理重复代码
- 改进命名
- 如有需要,提取函数/类
- 每次更改后运行测试
测试组织
文件结构
项目/
src/
模块.py
tests/
conftest.py # 共享夹具
test_模块.py # 模块.py 的测试
pyproject.toml # Pytest 配置
命名约定
- 测试文件:
test_*.py或*_test.py - 测试函数:
test_* - 测试类:
Test* - 夹具:描述性名称(
mock_database,sample_user)
Pytest 最佳实践
夹具
import pytest
@pytest.fixture
def sample_config():
return {"key": "value"}
@pytest.fixture
def mock_client(mocker):
return mocker.MagicMock()
参数化
@pytest.mark.parametrize("输入,预期", [
("hello", "HELLO"),
("world", "WORLD"),
("", ""),
])
def test_大写转换(输入, 预期):
assert 输入.upper() == 预期
异步测试
import pytest
@pytest.mark.asyncio
async def test_异步函数():
result = await async_operation()
assert result == expected
异常测试
def test_抛出值错误():
with pytest.raises(ValueError, match="无效输入"):
process_input(None)
运行测试
使用 uv
uv run pytest # 运行所有测试
uv run pytest tests/test_module.py # 运行特定文件
uv run pytest -k "test_name" # 按名称模式运行
uv run pytest -v --tb=short # 详细输出,简短回溯
uv run pytest --cov=src --cov-report=term # 带覆盖率
常用标志
-v/--verbose- 详细输出-x/--exitfirst- 首次失败时停止--tb=short- 简短回溯--tb=no- 无回溯-k EXPR- 运行匹配表达式的测试-m MARKER- 运行带标记的测试--cov=PATH- 指定路径的覆盖率--cov-report=term-missing- 显示缺失行
pyproject.toml 配置
最小化设置
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
完整配置
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_functions = ["test_*"]
python_classes = ["Test*"]
addopts = "-v --tb=short"
markers = [
"slow: 标记为慢速测试",
"integration: 标记为集成测试",
]
filterwarnings = [
"ignore::DeprecationWarning",
]
[tool.coverage.run]
source = ["src"]
branch = true
omit = ["tests/*", "*/__init__.py"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
]
fail_under = 80
show_missing = true
报告生成
TESTING_REPORT.local.md 文件应包含:
- 测试执行摘要(通过/失败/跳过)
- 按模块划分的覆盖率指标
- 按严重性划分的审计发现
- 带文件:行号引用的建议
- 证据(命令输出)
与对话集成
当用户要求编写测试时:
- 检查对话历史以获取关于测试内容的上下文
- 识别正在讨论的代码/功能
- 如果不清楚,请提出澄清问题:
- “我应该测试什么具体行为?”
- “我应该包含 X 的边缘情况吗?”
- “您需要单元测试、集成测试还是两者都要?”
- 遵循 TDD:首先编写失败的测试,然后实现
可用命令
/tdd-pytest:init- 初始化 pytest 配置/tdd-pytest:test [路径]- 使用 TDD 编写测试(上下文感知)/tdd-pytest:test-all- 运行所有测试/tdd-pytest:report- 生成/更新 TESTING_REPORT.local.md