Files
bruno 2cb4ddc4c0 feat: complete Week 1-4 optimization implementation
Major Updates:
- ✅ Implemented 4 Claude Code Skills (2600+ lines)
  - code-review: Security, quality, type checking
  - test-generator: Auto-generate pytest tests
  - doc-updater: Auto-update README and API docs
  - refactor-assistant: Code smell detection

- ✅ Implemented 2 Git Hooks (450+ lines)
  - pre-commit: Auto-format, lint, review
  - pre-push: Test suite and coverage check

- 📚 Complete documentation (20+ files)
  - Skills READMEs with examples
  - Optimization roadmap and progress
  - TODO list with 22 tasks
  - Quick reference guide

- 📊 Progress: 45% → 64% (Phase 1: 20% → 60%)

- 💰 ROI: Saving 50.6 hours/month ≈ 6.3 person-days/month

Next Steps:
- API Designer Skill
- Code templates library
- Prompt library
- GitHub Projects task tracking

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 12:10:29 +08:00
..

Test Generator Skill

自动生成全面的单元测试,支持 pytest 框架,智能分析代码结构生成测试用例。

功能

  • 🧪 自动测试生成 - 分析 Python 代码并生成测试用例
  • 📊 代码覆盖率 - 集成 pytest-cov 进行覆盖率分析
  • 🎯 智能分析 - 识别函数、类、方法和边界情况
  • 🔧 多种测试模式 - 支持成功案例、边界情况、错误处理
  • 🎭 Mock 支持 - 自动识别需要 mock 的外部依赖
  • ✨ 最佳实践 - 遵循 AAA 模式(Arrange-Act-Assert)

安装

必需依赖

# Git(通常已安装)
git --version

# Python 3.8+
python3 --version

推荐依赖

# 安装 pytest 和相关工具
pip install pytest pytest-cov pytest-asyncio pytest-mock

# 验证安装
pytest --version

使用方法

基本使用

# 为所有变更的文件生成测试
python3 .claude/skills/test-generator/generate.py

# 为特定目录生成测试
python3 .claude/skills/test-generator/generate.py --target src/api/

# 为特定文件生成测试
python3 .claude/skills/test-generator/generate.py --target src/utils.py

高级选项

# 指定测试框架
python3 .claude/skills/test-generator/generate.py --framework pytest

# 设置目标覆盖率
python3 .claude/skills/test-generator/generate.py --coverage-threshold 90

# 生成后立即运行测试
python3 .claude/skills/test-generator/generate.py --run-tests

# 完整命令示例
python3 .claude/skills/test-generator/generate.py \
  --target src/ \
  --framework pytest \
  --coverage-threshold 85 \
  --run-tests

与 Claude Code 集成

方式 1: 直接调用

# 在 Claude Code 中
"请生成测试"
"为 src/api/ 目录生成测试"
"生成测试并运行"
# Claude 会调用这个 skill

方式 2: 开发工作流

# 1. 开发新功能
# 2. 使用 test-generator 生成初始测试
python3 .claude/skills/test-generator/generate.py --target src/new_feature.py

# 3. 审查生成的测试
cat tests/test_new_feature.py

# 4. 完善测试用例(添加具体断言)
# 5. 运行测试确保通过
pytest tests/test_new_feature.py -v

# 6. 检查覆盖率
pytest tests/test_new_feature.py --cov=src.new_feature --cov-report=term-missing

方式 3: Git Hook 自动生成

在 .git/hooks/pre-commit 中添加:

#!/bin/bash

# 获取变更的 Python 文件
changed_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$' | grep -v '^test_')

if [ -n "$changed_files" ]; then
    echo "🧪 Generating tests for changed files..."

    for file in $changed_files; do
        # 检查是否已有测试文件
        test_file="tests/test_$(basename $file)"

        if [ ! -f "$test_file" ]; then
            echo "   Creating $test_file..."
            python3 .claude/skills/test-generator/generate.py --target "$file"

            # 将生成的测试添加到 staging
            git add "$test_file"
        fi
    done
fi

方式 4: GitHub Actions

# .github/workflows/auto-test-generation.yml
name: Auto Test Generation

on:
  pull_request:
    paths:
      - '**.py'
      - '!tests/**'

jobs:
  generate-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install pytest pytest-cov

      - name: Generate missing tests
        run: |
          # 获取 PR 中变更的文件
          changed_files=$(git diff --name-only origin/main...HEAD | grep '\.py$' | grep -v '^test_')

          for file in $changed_files; do
            test_file="tests/test_$(basename $file)"
            if [ ! -f "$test_file" ]; then
              python3 .claude/skills/test-generator/generate.py --target "$file"
            fi
          done

      - name: Commit generated tests
        run: |
          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git add tests/
          git commit -m "chore: auto-generate tests for PR changes" || echo "No new tests to commit"
          git push

输出示例

🧪 Starting test generation...

📁 Found 3 source files

📝 Analyzing src/api/auth.py...
   Found 2 functions, 1 classes
   ✅ Generated tests/test_auth.py

📝 Analyzing src/utils.py...
   Found 5 functions, 0 classes
   ✅ Generated tests/test_utils.py

📝 Analyzing src/models.py...
   Found 0 functions, 3 classes
   ✅ Generated tests/test_models.py

================================================================================
🧪 TEST GENERATION REPORT
================================================================================

Total Files: 3
Framework: pytest
Target Coverage: 80%

Generated Tests:
--------------------------------------------------------------------------------

📄 src/api/auth.py
   → tests/test_auth.py
   Functions: 2, Classes: 1

📄 src/utils.py
   → tests/test_utils.py
   Functions: 5, Classes: 0

📄 src/models.py
   → tests/test_models.py
   Functions: 0, Classes: 3

================================================================================
✅ Test generation completed!

Next steps:
1. Review generated tests and add assertions
2. Run tests: pytest tests/
3. Check coverage: pytest --cov=. --cov-report=html
4. Iterate until coverage >= 80%
================================================================================

生成的测试示例

假设有源文件 src/utils.py:

def calculate_total(prices: List[float], tax_rate: float = 0.1) -> float:
    """Calculate total with tax"""
    subtotal = sum(prices)
    return subtotal * (1 + tax_rate)

生成的测试文件 tests/test_utils.py:

"""
Tests for src/utils.py
Auto-generated by test-generator skill
"""

import pytest
from unittest.mock import Mock, patch, MagicMock

# Import module under test
from src.utils import calculate_total


# Fixtures
@pytest.fixture
def sample_data():
    """Sample test data"""
    return {
        "test_string": "test",
        "test_int": 42,
        "test_list": [1, 2, 3],
        "test_dict": {"key": "value"}
    }


class TestCalculateTotal:
    """Tests for calculate_total"""

    def test_calculate_total_success(self):
        """Test calculate_total with valid inputs"""
        # Arrange
        prices = [10.0, 20.0, 30.0]
        tax_rate = 0.1

        # Act
        result = calculate_total(prices, tax_rate)

        # Assert
        assert result is not None
        assert isinstance(result, float)
        assert result == 66.0  # (10+20+30) * 1.1

    def test_calculate_total_edge_cases(self):
        """Test calculate_total with edge case inputs"""
        # Empty list
        assert calculate_total([]) == 0.0

        # Single item
        assert calculate_total([10.0]) == 11.0

        # Zero tax
        assert calculate_total([10.0, 20.0], 0.0) == 30.0

        # Negative tax (discount)
        assert calculate_total([100.0], -0.1) == 90.0

    def test_calculate_total_error_handling(self):
        """Test calculate_total error handling"""
        # Test with invalid inputs
        with pytest.raises(TypeError):
            calculate_total(None)

        with pytest.raises(TypeError):
            calculate_total([10.0], "invalid")

配置

编辑 skill.json 自定义设置:

{
  "configuration": {
    "test_framework": "pytest",
    "coverage_threshold": 80,
    "test_directory": "tests",
    "naming_pattern": "test_{filename}.py",
    "include_fixtures": true,
    "include_mocks": true,
    "include_parametrize": true
  }
}

配置选项说明

  • test_framework: 测试框架(pytest 或 unittest)
  • coverage_threshold: 目标代码覆盖率百分比
  • test_directory: 测试文件存放目录
  • naming_pattern: 测试文件命名模式
  • include_fixtures: 是否生成 pytest fixtures
  • include_mocks: 是否生成 mock 示例
  • include_parametrize: 是否使用 parametrize(未来实现)

测试模式

生成的测试包含以下模式:

1. 成功路径测试(Happy Path)

def test_function_success(self):
    """Test with valid inputs"""
    # Arrange
    input_data = "valid"

    # Act
    result = function(input_data)

    # Assert
    assert result is not None

2. 边界情况测试(Edge Cases)

def test_function_edge_cases(self):
    """Test with edge case inputs"""
    # Empty input
    assert function("") == expected_empty

    # None input
    assert function(None) == expected_none

    # Large input
    assert function("x" * 10000) == expected_large

3. 错误处理测试(Error Handling)

def test_function_error_handling(self):
    """Test error handling"""
    with pytest.raises(ValueError):
        function(invalid_input)

    with pytest.raises(TypeError):
        function(wrong_type)

4. Mock 测试(Mocking Dependencies)

@patch("module.external_api")
def test_function_with_mock(self, mock_api):
    """Test with mocked dependencies"""
    # Arrange
    mock_api.return_value = Mock(status=200)

    # Act
    result = function()

    # Assert
    mock_api.assert_called_once()
    assert result.status == 200

运行测试

基本测试运行

# 运行所有测试
pytest tests/

# 运行特定测试文件
pytest tests/test_utils.py

# 运行特定测试类
pytest tests/test_utils.py::TestCalculateTotal

# 运行特定测试方法
pytest tests/test_utils.py::TestCalculateTotal::test_calculate_total_success

# 详细输出
pytest tests/ -v

# 显示 print 输出
pytest tests/ -s

覆盖率分析

# 基本覆盖率
pytest tests/ --cov=src

# 详细覆盖率(显示未覆盖的行)
pytest tests/ --cov=src --cov-report=term-missing

# HTML 覆盖率报告
pytest tests/ --cov=src --cov-report=html
# 打开 htmlcov/index.html

# 只显示覆盖率低于阈值的文件
pytest tests/ --cov=src --cov-fail-under=80

并行运行

# 安装 pytest-xdist
pip install pytest-xdist

# 使用多核运行
pytest tests/ -n auto

# 指定进程数
pytest tests/ -n 4

最佳实践

1. 渐进式生成

# 先为核心模块生成测试
python3 .claude/skills/test-generator/generate.py --target src/core/

# 检查生成的测试
cat tests/test_core.py

# 完善测试用例
# 编辑 tests/test_core.py,添加具体断言

# 运行测试确保通过
pytest tests/test_core.py -v

# 然后逐步扩展到其他模块

2. 审查并完善生成的测试

生成的测试是起点而非终点。需要:

  • ✅ 添加具体的断言值
  • ✅ 补充业务逻辑相关的测试用例
  • ✅ 添加真实的边界条件
  • ✅ 完善 mock 配置
  • ✅ 添加文档字符串

3. 结合 TDD 工作流

# 方案 1: 先写代码,后生成测试框架
# 1. 编写功能代码
# 2. 生成测试框架
python3 .claude/skills/test-generator/generate.py --target src/new_feature.py
# 3. 完善测试用例
# 4. 运行测试并修复

# 方案 2: 先生成测试框架,再实现功能
# 1. 创建空的源文件(只有函数签名)
# 2. 生成测试框架
# 3. 完善测试用例(TDD 的 "Red" 阶段)
# 4. 实现功能(TDD 的 "Green" 阶段)
# 5. 重构(TDD 的 "Refactor" 阶段)

4. 持续维护

# 定期检查测试覆盖率
pytest tests/ --cov=src --cov-report=term-missing

# 识别未覆盖的代码
# 为这些代码补充测试

# 运行变异测试(需要 mutmut)
pip install mutmut
mutmut run

5. CI/CD 集成

确保测试在 CI 中运行:

# .github/workflows/test.yml
- name: Run tests with coverage
  run: |
    pytest tests/ \
      --cov=src \
      --cov-report=xml \
      --cov-report=term-missing \
      --cov-fail-under=80

- name: Upload coverage to Codecov
  uses: codecov/codecov-action@v3
  with:
    file: ./coverage.xml

故障排查

问题:生成的测试无法运行

# 检查 pytest 是否安装
pytest --version

# 安装缺失的依赖
pip install pytest pytest-cov pytest-asyncio

# 检查导入路径
# 确保 src/ 在 PYTHONPATH 中
export PYTHONPATH="${PYTHONPATH}:${PWD}"

问题:无法找到源文件

# 检查目标路径
ls -la src/

# 使用绝对路径
python3 .claude/skills/test-generator/generate.py --target /absolute/path/to/file.py

# 检查 git 状态
git status
git diff --name-only

问题:生成的测试过于简单

这是预期的!生成的测试是框架,需要手动完善:

  1. 添加真实的测试数据
  2. 补充具体的断言
  3. 添加业务逻辑相关的测试场景
  4. 完善 mock 配置

问题:异步函数测试不工作

# 安装 pytest-asyncio
pip install pytest-asyncio

# 在测试文件开头添加
import pytest

@pytest.mark.asyncio
async def test_async_function():
    result = await async_function()
    assert result is not None

扩展

添加自定义测试模板

编辑 generate.py 中的 _generate_function_tests() 方法:

def _generate_function_tests(self, func: FunctionInfo) -> List[str]:
    lines = []

    # 你的自定义测试模板
    lines.append(f'def test_{func.name}_custom_scenario(self):')
    lines.append(f'    """Custom test scenario"""')
    lines.append(f'    # Your custom test logic')
    lines.append(f'    pass')

    return lines

支持其他测试框架

# 添加 unittest 支持
if self.framework == 'unittest':
    lines.append('import unittest')
    lines.append('')
    lines.append(f'class Test{class_name}(unittest.TestCase):')
    # ... unittest 测试生成逻辑

集成其他工具

# 使用 hypothesis 进行属性测试
pip install hypothesis

# 使用 faker 生成测试数据
pip install faker

# 使用 freezegun 模拟时间
pip install freezegun

参考资源


版本: 1.0.0 创建时间: 2024-12-30 维护者: DevOps Team