241 lines
11 KiB
Markdown
241 lines
11 KiB
Markdown
---
|
||
title: "feat: GEO P1 — Migration Verification, Core Flow Integration Tests & Test Suite Stabilization"
|
||
type: feat
|
||
status: completed
|
||
date: 2026-06-04
|
||
---
|
||
|
||
# GEO P1 — Migration Verification, Core Flow Integration Tests & Test Suite Stabilization
|
||
|
||
## Summary
|
||
|
||
完成 P1 阶段三项核心工作:修复数据库迁移验证(required_tables 不匹配、alembic.ini 硬编码密码、单迁移文件 drift 检测)、补充核心变现链路深度集成测试(注册→品牌→诊断→策略→内容→分发→监控闭环)、清理剩余测试失败(测试隔离污染和 API 签名漂移)。完成后平台核心业务流可端到端跑通,测试套件稳定可依赖。
|
||
|
||
## Problem Frame
|
||
|
||
Plan 008/009 的生产加固工作已完成,P0 外部事项(ICP 备案、支付商户)在审批中。当前阻塞生产信心的代码层面问题有三:
|
||
|
||
1. **数据库迁移验证失效** — `test_database_migration.py` 中 `required_tables` 列表与实际 schema 严重不一致(5+ 表名错误或不存在),`alembic.ini` 硬编码数据库密码,仅有一个初始迁移文件无法检测 schema drift
|
||
2. **核心业务流从未端到端跑通** — 30+ API 模块中仅认证/查询/引用/品牌/支付有集成测试,核心变现闭环(品牌→诊断→策略→内容→分发→监控)缺少深度集成验证
|
||
3. **测试套件不稳定** — 81 failed + 33 errors,主要根因是 `app.dependency_overrides` 污染(测试间隔离失效)和 API 签名漂移(测试与实际接口不一致)
|
||
|
||
---
|
||
|
||
## Requirements
|
||
|
||
**数据库迁移验证**
|
||
|
||
R1. `test_database_migration.py` 中 `required_tables` 列表与实际 schema 完全一致
|
||
R2. `alembic.ini` 不包含硬编码数据库密码,统一从环境变量读取
|
||
R3. `alembic check` 可正确检测模型与迁移的 drift,drift 存在时测试失败
|
||
R4. 迁移测试在 CI 环境(无 PostgreSQL)中可正确 skip 而非 error
|
||
|
||
**核心链路集成测试**
|
||
|
||
R5. 品牌创建→诊断→GEO 方案→内容生成→分发→监控的完整闭环有深度集成测试
|
||
R6. 集成测试使用真实异步数据库会话(非 mock),验证数据在各模块间正确流转
|
||
R7. 集成测试覆盖关键错误路径(品牌不存在、配额超限、权限隔离)
|
||
|
||
**测试套件稳定化**
|
||
|
||
R8. `app.dependency_overrides` 在每个测试后正确清理,消除测试间污染
|
||
R9. API 测试中 mock 数据与实际接口签名一致,消除签名漂移导致的失败
|
||
R10. 全量测试运行失败数降至 20 以下
|
||
|
||
---
|
||
|
||
## Key Technical Decisions
|
||
|
||
KTD1. **迁移测试采用"先修正 required_tables,再添加 drift 检测"策略。** 修正 `required_tables` 是最小改动修复现有测试;添加 `alembic check` 测试确保未来 schema 变更不会遗漏迁移文件。不生成增量迁移文件 — 当前模型与单迁移文件一致,无需拆分。
|
||
|
||
KTD2. **核心链路集成测试使用 SQLite 内存数据库 + 真实异步会话。** 与现有 `test_full_flow.py` 和 `test_business_flow.py` 保持一致,避免引入 PostgreSQL 测试依赖。对于 PostgreSQL 特有功能(ENUM 类型),在测试中用 String 替代或标记 skip。这确保 CI 可运行且测试速度不受数据库启动影响。
|
||
|
||
KTD3. **测试隔离采用 `app.dependency_overrides` 自动清理 fixture。** 在 `tests/conftest.py` 中添加 `autouse=True` 的 cleanup fixture,确保每个测试后 `app.dependency_overrides.clear()` 被调用。这是最小侵入的修复方式,不需要修改每个测试文件。
|
||
|
||
KTD4. **API 签名漂移采用"测试适配实际"策略。** 不修改 API 实现来适应测试,而是修正测试中的 mock 数据和断言以匹配当前 API 签名。对于已废弃的 API 端点,删除对应测试而非维护死代码。
|
||
|
||
---
|
||
|
||
## Implementation Units
|
||
|
||
### U1. 修复数据库迁移测试
|
||
|
||
**Goal:** 修正 `required_tables` 列表、清理 `alembic.ini` 硬编码密码、添加 drift 检测测试
|
||
|
||
**Requirements:** R1, R2, R3, R4
|
||
|
||
**Dependencies:** none
|
||
|
||
**Files:**
|
||
- `backend/tests/test_infrastructure/test_database_migration.py` — 修正 required_tables,添加 drift 检测测试
|
||
- `backend/alembic.ini` — 移除硬编码数据库 URL
|
||
- `backend/alembic/env.py` — 确认已从 settings 读取 DATABASE_URL
|
||
|
||
**Approach:**
|
||
1. 从 `alembic/versions/a79329c23b20_initial_complete_schema.py` 中提取实际表名列表,替换 `required_tables`
|
||
2. `alembic.ini` 中 `sqlalchemy.url` 留空或使用占位符(`env.py` 已覆盖此值)
|
||
3. 添加 `test_alembic_check_detects_drift` 测试:临时修改一个 model 字段,运行 `alembic check`,验证检测到 drift,然后恢复
|
||
4. 为所有需要真实数据库的测试添加 `@pytest.mark.skipif` 条件(检查数据库连接可用性)
|
||
|
||
**Test scenarios:**
|
||
- `required_tables` 中每个表名在迁移文件中存在对应 `create_table` 调用
|
||
- `alembic.ini` 不包含明文密码
|
||
- drift 检测测试在 schema 不匹配时失败
|
||
- 无数据库连接时测试 skip 而非 error
|
||
|
||
**Verification:** `pytest tests/test_infrastructure/test_database_migration.py --no-cov` 全部通过或正确 skip
|
||
|
||
---
|
||
|
||
### U2. 核心变现链路集成测试
|
||
|
||
**Goal:** 品牌创建→诊断→GEO 方案→内容生成→分发→监控的深度集成测试
|
||
|
||
**Requirements:** R5, R6, R7
|
||
|
||
**Dependencies:** U1(确保迁移测试不阻塞)
|
||
|
||
**Files:**
|
||
- `backend/tests/test_integration/test_core_monetization_flow.py` — 新建,核心变现闭环测试
|
||
- `backend/tests/test_integration/test_detection_flow.py` — 新建,定时检测任务流测试
|
||
- `backend/tests/test_integration/test_content_distribution_flow.py` — 新建,内容生成→分发流测试
|
||
|
||
**Approach:**
|
||
1. **核心变现闭环** (`test_core_monetization_flow.py`):
|
||
- 用户注册→登录→创建品牌→运行诊断→获取 GEO 方案→生成优化内容→创建分发计划→查看监控数据
|
||
- 验证数据在各步骤间正确流转(品牌 ID 贯穿、诊断结果可被方案引用、内容关联到品牌)
|
||
- 错误路径:品牌不存在返回 404、free 用户配额超限返回 403、用户间数据隔离
|
||
|
||
2. **定时检测流** (`test_detection_flow.py`):
|
||
- 创建检测任务→触发执行→查看结果→更新任务→删除任务
|
||
- 验证任务状态机转换正确(pending→running→completed/failed)
|
||
|
||
3. **内容分发流** (`test_content_distribution_flow.py`):
|
||
- 生成内容→创建分发计划→执行分发→查看分发状态
|
||
- 验证平台规则校验(min_tags/max_tags)
|
||
|
||
**Patterns to follow:** `backend/tests/test_integration/test_business_flow.py`(现有集成测试模式:async_session fixture + 真实服务调用 + 数据验证)
|
||
|
||
**Test scenarios:**
|
||
- 核心闭环:注册→品牌→诊断→方案→内容→分发→监控,每步数据正确传递
|
||
- 错误路径:品牌不存在 404、配额超限 403、权限隔离
|
||
- 检测任务:创建→触发→查看→更新→删除完整生命周期
|
||
- 内容分发:生成→分发→状态更新,平台规则校验生效
|
||
|
||
**Verification:** `pytest tests/test_integration/ --no-cov` 全部通过
|
||
|
||
---
|
||
|
||
### U3. 测试隔离修复
|
||
|
||
**Goal:** 消除 `app.dependency_overrides` 污染,确保测试间完全隔离
|
||
|
||
**Requirements:** R8
|
||
|
||
**Dependencies:** none
|
||
|
||
**Files:**
|
||
- `backend/tests/conftest.py` — 添加 autouse cleanup fixture
|
||
- `backend/tests/fixtures/database.py` — 确认 session fixture 正确清理
|
||
|
||
**Approach:**
|
||
1. 在 `conftest.py` 中添加 `@pytest.fixture(autouse=True)` 的 `_cleanup_dependency_overrides` fixture,在 yield 后调用 `app.dependency_overrides.clear()`
|
||
2. 检查现有测试中手动清理 `dependency_overrides` 的代码,移除冗余清理(autouse fixture 已覆盖)
|
||
3. 验证:运行全量测试套件,确认无测试间污染
|
||
|
||
**Test scenarios:**
|
||
- 两个使用不同 `dependency_overrides` 的测试顺序运行,后者不受前者影响
|
||
- 全量运行与单独运行的测试结果一致
|
||
|
||
**Verification:** 全量 `pytest tests/ --no-cov` 失败数显著下降
|
||
|
||
---
|
||
|
||
### U4. API 签名漂移修复
|
||
|
||
**Goal:** 修正测试中 mock 数据与实际 API 签名的不一致
|
||
|
||
**Requirements:** R9, R10
|
||
|
||
**Dependencies:** U3(先修复隔离问题,避免误判)
|
||
|
||
**Files:**
|
||
- `backend/tests/test_api/` — 修正 mock 数据和断言
|
||
- `backend/tests/test_services/` — 修正服务层测试签名
|
||
|
||
**Approach:**
|
||
1. 运行全量测试,收集所有 FAILED 和 ERROR 测试
|
||
2. 按错误类型分类:import 错误、参数不匹配、返回值结构不匹配、fixture 缺失
|
||
3. 批量修复同类错误(如同一服务的多个测试共享同一 mock 模式)
|
||
4. 对于已废弃的 API 端点测试,删除而非维护
|
||
5. 目标:全量失败数降至 20 以下
|
||
|
||
**Test scenarios:**
|
||
- 修复后的测试单独运行通过
|
||
- 修复后的测试在全量运行中通过(验证隔离修复有效)
|
||
|
||
**Verification:** `pytest tests/ --no-cov` 失败数 < 20
|
||
|
||
---
|
||
|
||
### U5. Plan 008/009 状态关闭
|
||
|
||
**Goal:** 将已完成的 Plan 008 和 Plan 009 标记为 completed
|
||
|
||
**Requirements:** implicit
|
||
|
||
**Dependencies:** U1-U4
|
||
|
||
**Files:**
|
||
- `docs/plans/2026-06-04-008-chore-geo-production-readiness-plan.md` — status: active → completed
|
||
- `docs/plans/2026-06-04-009-chore-geo-production-hardening-test-infra-plan.md` — status: active → completed
|
||
|
||
**Approach:** 将两个计划文件的 frontmatter `status` 改为 `completed`
|
||
|
||
**Test expectation:** none — 文档变更
|
||
|
||
**Verification:** 文件中 `status: completed`
|
||
|
||
---
|
||
|
||
## Scope Boundaries
|
||
|
||
### In Scope
|
||
- 数据库迁移测试修复和 drift 检测
|
||
- 核心变现链路深度集成测试(3 个新测试文件)
|
||
- 测试隔离和 API 签名漂移修复
|
||
- Plan 008/009 状态关闭
|
||
|
||
### Out of Scope
|
||
- P0 外部事项(ICP 备案、支付商户申请、域名部署)
|
||
- 全模块浅层冒烟测试(15+ 未覆盖模块的 1-2 个冒烟测试)
|
||
- 性能/负载测试(Locust/k6)
|
||
- 前端组件单元测试扩展
|
||
- 数据库增量迁移文件生成(当前模型与单迁移文件一致)
|
||
- Next.js 15 / Tailwind 4 升级
|
||
- 视觉回归测试
|
||
|
||
### Deferred to Follow-Up Work
|
||
- 剩余 15+ API 模块的集成测试补充
|
||
- PostgreSQL 兼容性集成测试(需 Testcontainers 或真实 PG 实例)
|
||
- 性能基线测试
|
||
- 前端测试覆盖率提升
|
||
|
||
---
|
||
|
||
## Risks & Dependencies
|
||
|
||
| 风险 | 影响 | 缓解 |
|
||
|------|------|------|
|
||
| SQLite 与 PostgreSQL 行为差异 | 集成测试可能无法捕获 PG 特有问题 | 核心业务逻辑不依赖 PG 特有功能;ENUM 类型在测试中用 String 替代 |
|
||
| API 签名漂移修复量大 | 81+ 失败需逐个分析 | 按错误类型批量修复,优先修复影响最多的模式 |
|
||
| `dependency_overrides` 清理可能破坏部分测试 | 某些测试可能依赖前一个测试的 override | 逐个验证,必要时调整测试顺序 |
|
||
| 核心链路测试依赖的服务可能未完全实现 | 某些服务方法可能是 stub | 测试中标记 `@pytest.mark.skip` 并记录 TODO |
|
||
|
||
---
|
||
|
||
## Open Questions
|
||
|
||
1. **`alembic check` 在 SQLite 环境下是否可用?** — 如果不可用,drift 检测测试需要标记为需要 PostgreSQL
|
||
2. **核心变现链路中哪些服务方法已完整实现?** — 需要在 U2 实现时逐个验证,未实现的标记 skip
|