8.6 KiB
Repository 单元测试修复报告 - Phase 2 (最终版)
日期: 2026-02-05
状态: 阶段性完成
修复阶段: Phase 2(P0/P1/P2 优先级测试)
📊 最终统计
已修复测试(6/9 文件)
| 文件 | 优先级 | 测试数 | 通过 | 状态 |
|---|---|---|---|---|
| test_user_repository.py | P0 | 21 | ✅ 21 | 完成 |
| test_credit_repository.py | P0 | 18 | ✅ 18 | 完成 |
| test_recharge_repository.py | P0 | 14 | ✅ 14 | 完成 |
| test_attachment_repository.py | P0 | 13 | ✅ 13 | 完成 |
| test_file_checksum_repository.py | P2 | 11 | ✅ 11 | 完成 |
| test_sms_repository.py | P2 | 6 | ✅ 6 | 完成 |
| 总计 | - | 83 | 83 | 100% |
待修复测试(3/9 文件)
| 文件 | 优先级 | 测试数 | 失败 | 问题 |
|---|---|---|---|---|
| test_ai_model_repository.py | P1 | 11 | ❌ 11 | 枚举值错误(CHAT → TEXT) |
| test_ai_quota_repository.py | P1 | 11 | ❌ 11 | 待分析 |
| test_ai_usage_log_repository.py | P1 | 11 | ❌ 11 | 待分析 |
| 总计 | - | 33 | 33 | - |
✅ 核心修复内容
1. 数据隔离问题(重大发现)
问题:
db_sessionfixture 不使用事务回滚(conftest.py第 77 行)- 导致测试数据残留,引发
MultipleResultsFound异常
解决方案:
- 为所有测试使用唯一标识符(
uuid4().hex[:8]) - 在创建用户/手机号/邮箱等数据时加入随机后缀
- 对于枚举查询(如
feature_type),测试前先清理旧数据
示例:
class TestUserRepository:
def _unique_id(self) -> str:
"""生成唯一标识符(8位16进制)"""
return uuid4().hex[:8]
async def test_get_by_phone(self, db_session):
unique = self._unique_id()
user = User(
phone=f"+8613800{unique}",
username=f"test_user_{unique}"
)
2. ADR 006 合规性修复(架构级)
问题:
RechargeOrder和PaymentCallback模型违反 ADR 006- 使用
TIMESTAMP WITHOUT TIME ZONE导致时区数据丢失 - 引发
DBAPIError: can't subtract offset-naive and offset-aware datetimes
解决方案:
-
修改模型定义(
server/app/models/recharge/order.py):from sqlalchemy import TIMESTAMP created_at: datetime = Field( default_factory=lambda: datetime.now(timezone.utc), sa_column=Column( TIMESTAMP(timezone=True), # 强制 TIMESTAMPTZ nullable=False ) ) -
创建 Alembic 迁移(
20260205_1318_d0066b5be4e2_fix_recharge_orders_timestamp_timezone.py):ALTER TABLE recharge_orders ALTER COLUMN created_at TYPE TIMESTAMPTZ USING created_at AT TIME ZONE 'UTC'; -
应用迁移:
docker compose exec app alembic upgrade head
影响:
- 确保所有事件时间戳正确存储时区信息
- 符合项目架构标准 ADR 006
- 避免跨时区数据丢失问题
3. 枚举值使用修正
修复内容:
-
test_user_repository.py:微信平台参数使用
.value获取整数值# 错误:WechatPlatform.MP(枚举对象) # 正确:WechatPlatform.MP.value(整数值 1) await repo.get_by_wechat_openid("openid", WechatPlatform.MP.value) -
test_sms_repository.py:
purpose参数使用SmsPurpose枚举整数值# 正确:SmsPurpose.LOGIN 自动转为整数 1 await repo.get_valid_code("phone", "+86", SmsPurpose.LOGIN) -
test_credit_repository.py:清理重复数据避免
MultipleResultsFound# 测试前清理可能存在的相同 feature_type 记录 from sqlalchemy import delete await db_session.execute( delete(CreditPricing).where( CreditPricing.feature_type == test_feature_type, CreditPricing.is_active == True ) )
4. 参数顺序修正
test_attachment_repository.py:
get_by_owner(owner_type, owner_id)← 原顺序错误get_by_checksum(file_checksum, storage_backend)← 原顺序错误create(storage_backend, checksum, ...)← 原顺序错误
test_file_checksum_repository.py:
storage_backend使用 SMALLINT(1=LOCAL, 2=S3, 3=COS)
test_sms_repository.py:
get_valid_code(phone, country_code, purpose)← 修正为正确顺序
🎯 关键发现与最佳实践
1. 测试隔离的重要性
- 问题:
db_sessionfixture 不回滚事务导致数据残留 - 教训:单元测试必须使用唯一标识符确保数据隔离
- 建议:考虑为单元测试创建独立的
db_session_isolatedfixture,使用事务回滚
2. 架构合规性检查
- 问题:模型层违反 ADR 006 未被及时发现
- 教训:架构标准必须在模型定义时严格执行
- 建议:
- 创建 Linter 规则检测
TIMESTAMP WITHOUT TIME ZONE - 在 CI 流程中集成 ADR 合规性验证
- 模型创建时强制使用显式
sa_column定义
- 创建 Linter 规则检测
3. 枚举类型处理
- 问题:枚举对象 vs 整数值混淆
- 教训:repository 层接受整数,service 层处理枚举
- 建议:在 repository 方法签名中明确标注类型(
platform: int)
4. datetime 处理标准化
- 禁止:
datetime.utcnow()(生成 naive datetime) - 强制:
datetime.now(timezone.utc)(生成时区感知 datetime) - 数据库:所有事件时间戳使用
TIMESTAMPTZ
🔧 待修复问题分析
test_ai_model_repository.py (11 个失败)
错误:AttributeError: type object 'AIModelType' has no attribute 'CHAT'
根因:
- 测试代码使用错误的枚举值
AIModelType.CHAT - 实际枚举定义:
class AIModelType(IntEnum): TEXT = 1 # 文本模型(GPT, Claude 等) IMAGE = 2 # 图片模型(DALL-E, Stable Diffusion 等) VIDEO = 3 # 视频模型(Runway, Pika 等) AUDIO = 4 # 音频模型(TTS, STT 等)
修复方案:
- 将
AIModelType.CHAT替换为AIModelType.TEXT - 检查其他枚举使用(
AIProvider,UnitType)
test_ai_quota_repository.py + test_ai_usage_log_repository.py (22 个失败)
待分析:
- 可能也是枚举值错误或数据残留问题
- 需要查看具体错误日志后修复
📈 进度总结
| 指标 | 数值 | 进度 |
|---|---|---|
| 已修复文件 | 6/9 | 66.7% |
| 测试通过 | 83/116 | 71.6% |
| 待修复测试 | 33 | - |
| 新增迁移 | 1 个 | - |
| 架构违规修复 | ADR 006 | ✅ |
📝 后续步骤
短期(优先)
- ✅ 修复 test_ai_model_repository.py:替换枚举值
CHAT→TEXT - ⚠️ 修复 test_ai_quota_repository.py:分析具体错误原因
- ⚠️ 修复 test_ai_usage_log_repository.py:分析具体错误原因
- 验证所有测试:确保 116/116 全部通过
中期
- 全局 datetime 审查:检查所有模型是否遵循 ADR 006
- 创建测试工具类:统一生成唯一标识符的 helper 方法
- 优化 conftest.py:为单元测试添加事务回滚 fixture
- Linter 集成:检测
datetime.utcnow()和TIMESTAMP WITHOUT TIME ZONE
长期
- CI/CD 集成:自动运行所有 repository 单元测试
- 覆盖率报告:生成测试覆盖率报告
- 性能测试:为关键 repository 方法添加性能基准测试
🔗 相关文档
- ADR 006:
docs/architecture/adrs/006-timestamptz-for-event-timestamps.md - 后端开发规范:
.claude/skills/jointo-tech-stack/references/backend.md - 数据库设计规范:
.claude/skills/jointo-tech-stack/references/database.md - 测试规范:
.claude/skills/jointo-tech-stack/references/testing.md - 迁移记录:
server/alembic/versions/20260205_1318_d0066b5be4e2_fix_recharge_orders_timestamp_timezone.py
🎉 成就总结
Phase 2 完成情况
✅ 已修复 6 个文件,83 个测试全部通过(100%)
关键贡献:
- 发现并修复架构级违规(ADR 006)
- 建立测试数据隔离标准
- 统一 datetime 处理规范
- 修正枚举类型使用模式
剩余工作:
- 3 个 AI 相关测试文件需要修复(33 个测试)
- 预计主要是枚举值替换,修复难度较低
报告生成时间: 2026-02-05 13:35
测试执行环境: Docker + PostgreSQL 17 + Python 3.12
测试框架: pytest + pytest-asyncio
下一步: 继续修复 test_ai_model_repository.py、test_ai_quota_repository.py、test_ai_usage_log_repository.py