测试样板生成器
⚠️ 必须先阅读项目文档
在生成测试之前,您必须阅读并理解以下项目文档:
核心项目文档
- README.md - 项目概览、特性和快速开始
- AI_DOCS/project-context.md - 技术栈、架构、开发工作流
- AI_DOCS/code-conventions.md - 代码风格、格式化、最佳实践(特别是测试)
- AI_DOCS/tdd-workflow.md - TDD流程、测试标准、覆盖率要求(关键)
会话上下文(如果可用)
- .ai-context/ACTIVE_TASKS.md - 当前任务和优先级
- .ai-context/CONVENTIONS.md - 项目特定约定
- .ai-context/RECENT_DECISIONS.md - 最近的架构决策
- .ai-context/LAST_SESSION_SUMMARY.md - 上次会话总结
额外的AI文档
- AI_DOCS/ai-tools.md - 会话管理工作流
- AI_DOCS/ai-skills.md - 其他专业技能/代理可用
为什么这很重要
- 测试标准:遵循项目特定的测试结构和约定
- TDD模式:使用AAA模式、适当的固定装置和参数化
- 代码质量:生成具有类型提示、文档字符串、正确导入的测试
- 模拟指南:了解何时模拟与使用真实代码
- 覆盖目标:生成帮助达到80%+覆盖率的测试
阅读这些文件后,请继续下面的测试生成任务。
概览
自动生成遵循该项目严格TDD和质量标准的全面测试样板。
何时使用
- 为新模块、类或函数创建测试
- 开始TDD工作流(首先编写测试!)
- 需要具有适当结构的测试模板
- 想要参数化测试示例
- 创建测试固定装置
此技能生成的内容
✅ 具有适当导入和结构的测试文件 ✅ 按功能组织的测试类 ✅ 参数化测试模板 ✅ AAA模式(安排-行动-断言)结构 ✅ 完整的类型提示 ✅ Google风格的文档字符串 ✅ 固定装置模板(如果需要)
使用示例
为模块生成测试
# 用户提供源文件
为src/python_modern_template/validators.py生成测试
输出: 创建tests/test_validators.py,包含:
- 每个函数/类的测试类
- 参数化测试用例
- 边缘情况测试模板
- 正确的导入和结构
为特定函数生成测试
# 用户描述函数
为validate_email函数生成测试,该函数检查电子邮件格式
输出: 创建测试类,包含:
- 基本功能测试
- 边缘情况(空的、无效格式、特殊字符)
- 参数化测试用例
- 错误处理测试
生成固定装置模板
# 用户需要测试固定装置
为数据库连接生成pytest固定装置
输出: 创建conftest.py条目,包含适当的固定装置结构
逐步过程
第1步:分析源代码
如果提供源文件:
- 读取源文件
- 识别所有公共函数和类
- 分析函数签名(参数、返回类型)
- 识别错误情况(引发子句)
如果由用户描述:
- 提取函数/类名称
- 理解参数和返回类型
- 从描述中识别测试场景
第2步:选择模板
从templates/中选择适当的模板:
test_function.py- 简单函数测试test_class.py- 类方法测试test_parametrized.py- 数据驱动测试test_async.py- 异步函数测试test_exception.py- 错误处理测试conftest_fixture.py- Pytest固定装置
第3步:生成测试代码
使用.claude/skills/test-generator/templates/目录中的模板。
模板变量:
{module_name}- 源模块名称{class_name}- 被测试的类{function_name}- 被测试的函数{test_class_name}- 生成的测试类名称{import_path}- 完整的导入路径{param_names}- 函数参数{return_type}- 函数返回类型
第4步:添加测试用例
生成测试用例:
- 快乐路径 - 正常成功执行
- 边缘情况 - 边界值、空输入、None值
- 错误情况 - 无效输入、异常
- 参数化情况 - 多种输入组合
第5步:格式化和保存
- 应用适当的格式化(Black,isort)
- 确保类型提示和文档字符串
- 保存到适当的测试文件
- 显示生成测试的摘要
模板参考
模板:简单函数测试
文件: templates/test_function.py
"""测试{module_name}.{function_name}。"""
从 __future__ 导入 annotations
导入 pytest
从 {import_path} 导入 {function_name}
类 Test{FunctionNameCamelCase}:
"""测试用例{function_name}。"""
def test_{function_name}_basic(self) -> None:
"""测试{function_name}的基本功能。"""
# 安排
# TODO: 设置测试数据
# 行动
result = {function_name}()
# 断言
# TODO: 添加断言
assert result is not None
def test_{function_name}_with_valid_input(self) -> None:
"""测试{function_name}与有效输入。"""
# 安排
# TODO: 准备有效输入
# 行动
# TODO: 调用函数
# 断言
# TODO: 验证结果
pass
def test_{function_name}_with_invalid_input(self) -> None:
"""测试{function_name}处理无效输入。"""
# 安排
# TODO: 准备无效输入
# 行动 & 断言
使用 pytest.raises(ValueError):
{function_name}() # TODO: 添加无效输入
def test_{function_name}_edge_cases(self) -> None:
"""测试{function_name}边缘情况。"""
# TODO: 测试空输入、None、边界值
pass
模板:参数化测试
文件: templates/test_parametrized.py
"""测试{module_name}.{function_name}。"""
从 __future__ 导入 annotations
导入 pytest
从 {import_path} 导入 {function_name}
类 Test{FunctionNameCamelCase}:
"""参数化测试用例{function_name}。"""
@pytest.mark.parametrize(
"input_value,expected",
[
# 快乐路径案例
("valid_input_1", "expected_output_1"),
("valid_input_2", "expected_output_2"),
# 边缘情况
("", "expected_for_empty"),
(None, "expected_for_none"),
# TODO: 添加更多测试用例
],
)
def test_{function_name}_parametrized(
self,
input_value: str, # TODO: 调整类型
expected: str, # TODO: 调整类型
) -> None:
"""测试{function_name}与各种输入。"""
# 行动
result = {function_name}(input_value)
# 断言
assert result == expected
@pytest.mark.parametrize(
"invalid_input,expected_error",
[
("invalid_1", ValueError),
("invalid_2", TypeError),
# TODO: 添加更多错误案例
],
)
def test_{function_name}_error_cases(
self,
invalid_input: str, # TODO: 调整类型
expected_error: type[Exception],
) -> None:
"""测试{function_name}引发适当的错误。"""
# 行动 & 断言
使用 pytest.raises(expected_error):
{function_name}(invalid_input)
模板:类方法测试
文件: templates/test_class.py
"""测试{module_name}.{class_name}。"""
从 __future__ 导入 annotations
导入 pytest
从 {import_path} 导入 {class_name}
类 Test{ClassName}:
"""测试用例{class_name}。"""
@pytest.fixture
def instance(self) -> {class_name}:
"""为测试创建{class_name}实例。"""
返回 {class_name}() # TODO: 添加初始化参数
def test_initialization(self, instance: {class_name}) -> None:
"""测试{class_name}初始化。"""
# 断言
assert isinstance(instance, {class_name})
# TODO: 验证初始状态
def test_method_name(self, instance: {class_name}) -> None:
"""测试method_name行为。"""
# 安排
# TODO: 设置测试数据
# 行动
result = instance.method_name() # TODO: 添加实际方法
# 断言
# TODO: 验证结果
assert result is not None
模板:异步函数测试
文件: templates/test_async.py
"""测试异步{module_name}.{function_name}。"""
从 __future__ 导入 annotations
导入 pytest
从 {import_path} 导入 {function_name}
类 Test{FunctionNameCamelCase}:
"""测试用例异步{function_name}。"""
@pytest.mark.asyncio
异步 def test_{function_name}_basic(self) -> None:
"""测试基本异步功能。"""
# 安排
# TODO: 设置测试数据
# 行动
result = 等待 {function_name}()
# 断言
assert result is not None
@pytest.mark.asyncio
异步 def test_{function_name}_concurrent(self) -> None:
"""测试并发执行。"""
# 安排
导入 asyncio
# 行动
结果 = 等待 asyncio.gather(
{function_name}(),
{function_name}(),
)
# 断言
assert 长度(结果) == 2
模板:Pytest固定装置
文件: templates/conftest_fixture.py
"""Pytest固定装置{test_module}。"""
从 __future__ 导入 annotations
从 collections.abc 导入 Generator
导入 pytest
@pytest.fixture
def {fixture_name}() -> Generator[{ResourceType}, None, None]:
"""为测试提供{description}。
产生:
{ResourceType}: {产生什么}
"""
# 设置
资源 = {ResourceType}() # TODO: 初始化资源
尝试:
产生 资源
最后:
# 拆除
通过 # TODO: 添加清理代码
质量标准
所有生成的测试必须包括:
✅ 类型提示
- 所有测试函数注释
-> None - 所有固定装置函数与适当的返回类型
- 所有参数与类型提示
✅ 文档字符串
- 每个测试函数都有描述性文档字符串
- 文档字符串解释WHAT正在测试,而不是HOW
- 清晰简洁
✅ AAA模式
def test_example() -> None:
"""测试描述。"""
# 安排 - 设置测试数据
数据 = prepare_test_data()
# 行动 - 执行函数
结果 = function_under_test(data)
# 断言 - 验证结果
assert 结果 == 预期
✅ 正确的导入
从 __future__ 导入 annotations # 总是第一
导入 pytest
从 python_modern_template.module 导入 function
✅ 没有过度模拟
- 尽可能使用真实代码
- 仅模拟:HTTP、DB、文件I/O、时间、随机
- 从不模拟:内部函数、验证器、处理器
输出格式
生成测试后,请提供:
## 生成的测试文件:tests/test_{module}.py
**摘要:**
- 测试类:X
- 测试函数:X
- 参数化测试:X
- 固定装置:X
- 代码行数:~XXX
**测试覆盖率:**
- 函数1:4个测试用例(快乐路径、边缘情况、错误处理)
- 函数2:3个测试用例
- 总计:X个测试用例
**下一步:**
1. 审查生成的测试并自定义TODO部分
2. 为您的用例添加特定的测试数据
3. 立即运行测试以验证它们失败(TDD红色阶段):
```bash
make test
- 实现功能
- 再次运行测试以验证它们通过
- 检查覆盖率:
make coverage
创建/修改的文件:
- ✅ tests/test_{module}.py (NEW)
- ⚠️ 记得在实际代码之前实现测试(TDD!)
## 与项目工具集成
此技能与以下集成:
- `make test` - 运行生成的测试
- `make coverage` - 验证测试覆盖率
- `make format` - 格式化生成的代码
- `tdd-reviewer`代理 - 验证TDD合规性
## 脚本使用
对于程序化生成,请使用:
```bash
# 从源文件生成
python .claude/skills/test-generator/scripts/generate.py \
--source src/python_modern_template/module.py \
--output tests/test_module.py
# 从函数名称生成
python .claude/skills/test-generator/scripts/generate.py \
--function validate_email \
--module validators \
--template parametrized
最佳实践
- 从生成的样板开始,然后自定义
- 审查所有TODO评论 - 用实际测试数据替换
- 立即运行测试 - 它们最初应该失败(TDD)
- 使用参数化测试 - 用于多个输入案例
- 避免过度模拟 - 尽可能使用真实代码
- 瞄准边缘情况 - 空的、None、无效、边界值
- 每个测试测试一件事 - 专注、清晰的断言
实际操作示例
示例1:为电子邮件验证器生成测试
用户请求:
为src/python_modern_template/validators.py中的validate_email函数生成测试
技能操作:
- 读取src/python_modern_template/validators.py
- 识别validate_email函数签名
- 选择参数化模板(多个测试用例)
- 生成tests/test_validators.py,包含:
- 有效的电子邮件案例
- 无效的电子邮件案例(没有@、多个@等)
- 边缘情况(空的、空白、非常长)
- 错误处理测试
示例2:为新类生成测试
用户请求:
我正在创建一个UserManager类,方法有:create_user、delete_user、find_user。生成测试。
技能操作:
- 选择类模板
- 生成测试类,包含:
- UserManager实例的固定装置
- 每个方法的测试
- 测试初始化
- 测试错误情况
- 为find_user添加参数化测试(各种搜索标准)
示例3:生成异步测试
用户请求:
为异步函数fetch_data(url: str) -> dict生成测试
技能操作:
- 选择异步模板
- 生成异步测试,包含:
- 基本获取测试与模拟HTTP
- 错误处理(超时、404、500)
- 并发获取测试
- 添加pytest-asyncio标记
记住
TDD工作流:
- 首先生成测试(此技能)
- 运行测试(它们应该失败)
- 实现代码
- 再次运行测试(它们应该通过)
- 在保持测试绿色的同时重构
此技能帮助您立即开始TDD - 测试第一,总是!