Files
2025-11-30 08:47:07 +08:00

8.1 KiB
Raw Permalink Blame History

name, description, version
name description version
backend-bugfix This skill should be used when the user asks to "debug backend tests", "fix pytest failures", "analyze Python errors", "fix FastAPI bugs", or mentions keywords like "pytest", "IntegrityError", "ValidationError", "SQLAlchemy", "FastAPI". It provides the complete bugfix workflow knowledge including error classification, confidence scoring, and TDD best practices for Python/FastAPI backends. 2.1.0

Backend Bugfix Workflow Skill

本 skill 提供后端测试 bugfix 的完整工作流知识,包括错误分类体系、置信度评分系统和 TDD 最佳实践。

错误分类体系

后端测试失败主要分为以下类型(按频率排序):

1. 数据库错误30%

症状:数据库连接失败、查询错误、事务问题

识别特征

  • IntegrityErrorOperationalError
  • sqlalchemy.exc.* 异常
  • UNIQUE constraint failed
  • 事务未提交或未回滚

解决策略:正确处理事务边界

# Before - 事务未正确处理
def create_user(db: Session, user: UserCreate):
    db_user = User(**user.dict())
    db.add(db_user)
    db.commit()  # 失败时无回滚
    return db_user

# After - 使用 try/except 确保事务安全
def create_user(db: Session, user: UserCreate):
    try:
        db_user = User(**user.dict())
        db.add(db_user)
        db.commit()
        db.refresh(db_user)
        return db_user
    except IntegrityError:
        db.rollback()
        raise HTTPException(status_code=409, detail="User already exists")

2. 验证错误25%

症状输入验证失败、Schema 不匹配

识别特征

  • ValidationError
  • pydantic.error_wrappers
  • 422 Unprocessable Entity
  • field required 错误

解决策略:完善 Pydantic Schema

# Before - 缺少验证
class UserCreate(BaseModel):
    email: str  # 没有格式验证

# After - 使用 Pydantic 验证器
class UserCreate(BaseModel):
    email: EmailStr

    @field_validator('email')
    @classmethod
    def email_must_be_valid(cls, v):
        if not v or '@' not in v:
            raise ValueError('Invalid email format')
        return v.lower()

3. API 错误20%

症状:端点返回错误状态码、路由不匹配

识别特征

  • HTTPException
  • 404 Not Found405 Method Not Allowed
  • 响应格式不符合预期

解决策略:检查路由定义和请求方法

# 确保端点定义正确
@router.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

4. 认证错误10%

症状:认证失败、权限不足

识别特征

  • 401 Unauthorized
  • 403 Forbidden
  • Token 相关错误
  • credentials 验证失败

解决策略:检查认证流程和 Token 处理

# 确保 Token 验证正确
async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: str = payload.get("sub")
        if user_id is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    return user_id

5. 异步错误8%

症状:异步操作超时、并发问题

识别特征

  • TimeoutError
  • CancelledError
  • asyncio 相关异常
  • 缺少 await 关键字

解决策略:正确使用 async/await

# Before - 忘记 await
async def get_data():
    result = fetch_from_external_api()  # 缺少 await
    return result

# After - 正确等待异步操作
async def get_data():
    result = await fetch_from_external_api()
    return result

6. 配置错误5%

症状:配置加载失败、环境变量缺失

识别特征

  • KeyError
  • environment 相关错误
  • settings 加载失败

解决策略:使用 Pydantic Settings 管理配置

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    secret_key: str

    class Config:
        env_file = ".env"

settings = Settings()

置信度评分系统

评分标准0-100

分数 级别 行为
80+ 自动执行
60-79 标记验证后继续
40-59 暂停询问用户
<40 不确定 停止收集信息

置信度计算

置信度 = 证据质量(40%) + 模式匹配(30%) + 上下文完整性(20%) + 可复现性(10%)

证据质量

  • 高:有完整堆栈、行号、可稳定复现
  • 中:有错误信息但缺上下文
  • 低:仅有模糊描述

模式匹配

  • 高:完全匹配已知错误模式
  • 中:部分匹配
  • 低:未知错误类型

上下文完整性

  • 高:测试代码 + 源代码 + 配置 + 数据库 Schema
  • 中:只有测试或源代码
  • 低:只有错误信息

可复现性

  • 高:每次运行都复现
  • 中:偶发(可能与数据或并发相关)
  • 低:环境相关

TDD 流程

RED Phase写失败测试

import pytest
from fastapi.testclient import TestClient

def test_create_user_duplicate_email(client: TestClient, db_session):
    """测试重复邮箱应返回 409"""
    # 1. 设置前置条件
    client.post("/api/users", json={"email": "test@example.com", "name": "User 1"})

    # 2. 执行被测操作
    response = client.post("/api/users", json={"email": "test@example.com", "name": "User 2"})

    # 3. 断言期望结果
    assert response.status_code == 409
    assert "already exists" in response.json()["detail"]

GREEN Phase最小实现

# 只写让测试通过的最小代码
# 不要优化,不要添加额外功能
def create_user(db: Session, user: UserCreate):
    existing = db.query(User).filter(User.email == user.email).first()
    if existing:
        raise HTTPException(status_code=409, detail="User already exists")
    # ... 创建用户逻辑

REFACTOR Phase重构

# 改善代码结构
# 保持测试通过
# 消除重复
# 提取公共逻辑到服务层

质量门禁

检查项 标准
测试通过率 100%
代码覆盖率 >= 90%
新代码覆盖率 100%
Lint (flake8) 无错误
TypeCheck (mypy) 无错误

pytest 常用模式

Fixtures

@pytest.fixture
def db_session():
    """创建测试数据库会话"""
    engine = create_engine("sqlite:///:memory:")
    Base.metadata.create_all(engine)
    Session = sessionmaker(bind=engine)
    session = Session()
    yield session
    session.close()

@pytest.fixture
def client(db_session):
    """创建测试客户端"""
    def override_get_db():
        yield db_session
    app.dependency_overrides[get_db] = override_get_db
    return TestClient(app)

异步测试

import pytest

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

参数化测试

@pytest.mark.parametrize("status_code,detail", [
    (400, "Invalid input"),
    (404, "Not found"),
    (409, "Already exists"),
])
def test_error_responses(client, status_code, detail):
    # 测试多种错误场景
    pass

常用命令

# 运行后端测试
make test TARGET=backend

# 运行特定测试
make test TARGET=backend FILTER=test_create_user

# 或使用 pytest 直接运行
pytest tests/ -k "test_create_user" -v

# 覆盖率检查
pytest --cov=app --cov-report=term-missing --cov-fail-under=90

# Lint 检查
flake8 app/ tests/

# 类型检查
mypy app/

# 完整 QA
make qa

相关文档

文档路径由配置指定(best_practices_dir),使用以下关键词搜索:

  • 测试最佳实践:关键词 "testing", "pytest", "backend"
  • 数据库操作:关键词 "database", "sqlalchemy", "transaction"
  • API 设计:关键词 "api", "endpoint", "fastapi"
  • 问题诊断:关键词 "troubleshooting", "debugging"