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 异步操作()
assert result == 预期
异常测试
def test_抛出值错误():
with pytest.raises(ValueError, match="无效输入"):
处理输入(None)
运行测试
使用uv
uv run pytest # 运行所有测试
uv run pytest tests/test_模块.py # 运行特定文件
uv run pytest -k "test_名称" # 按名称模式运行
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