diff --git a/docs/test-guide.md b/docs/test-guide.md new file mode 100644 index 0000000..ec8cfa1 --- /dev/null +++ b/docs/test-guide.md @@ -0,0 +1,89 @@ +# moziplus v2.0 测试操作指南 + +> 日期:2026-06-05 +> 对应设计文档:docs/test-plan-e2e-v27.md v3.0.1 +> 测试代码路径:`~/.sanguo_projects/sanguo_moziplus_v2/tests/` + +--- + +## 什么时候跑什么 + +| 场景 | 命令 | 耗时 | 说明 | +|------|------|------|------| +| **改了某个模块** | `pytest tests/unit/test_spawner.py` | <5s | 只跑改动的模块对应的单元测试 | +| **改了 API 层** | `pytest tests/integration/` | ~1min | 跑全部集成测试 | +| **提交前快速验证** | `pytest -m "not e2e"` | ~2min | 不跑 E2E,验证不破坏现有功能 | +| **部署前全量验证** | `RUN_INTEGRATION=1 pytest` | ~60min | 含 E2E,真实 Agent | +| **只跑 E2E 场景** | `RUN_INTEGRATION=1 pytest tests/e2e/test_e2e_scenarios.py` | ~30min | 串行,一个跑完再下一个 | +| **只跑 E2E 压力** | `RUN_INTEGRATION=1 pytest tests/e2e/test_e2e_stress.py` | ~10min | 并发测试 | + +## 按标记筛选 + +```bash +pytest -m broadcast # 广播相关 +pytest -m mail # 邮件相关 +pytest -m state_machine # 状态机 +pytest -m classify # Classify Outcome +pytest -m review # 审查/Rebuttal +``` + +## 改了什么跑什么(速查表) + +| 改的文件 | 跑什么 | +|---------|--------| +| `src/blackboard/db.py` | `pytest tests/unit/test_state_machine.py` | +| `src/daemon/spawner.py` | `pytest tests/unit/test_spawner.py tests/unit/test_classify_outcome.py` | +| `src/daemon/ticker.py` | `pytest tests/unit/test_broadcast_claim.py tests/integration/test_ticker_integration.py` | +| `src/daemon/dispatcher.py` | `pytest tests/unit/test_dispatcher.py` | +| `src/daemon/counter.py` | `pytest tests/unit/test_counter.py` | +| `src/daemon/router.py` | `pytest tests/unit/test_router.py` | +| `src/api/mail_routes.py` | `pytest tests/integration/test_api_mail.py` | +| `src/api/blackboard_routes.py` | `pytest tests/integration/ -k task` | +| `src/daemon/review.py` | `pytest tests/unit/test_review.py tests/integration/test_review_integration.py` | +| `frontend/` | 不在本范围 | + +## E2E 怎么跑 + +```bash +# 1. 确认 daemon 在线 +pm2 list | grep sanguo-moziplus-v2 + +# 2. 跑 E2E(串行场景,一个一个来) +RUN_INTEGRATION=1 pytest tests/e2e/test_e2e_scenarios.py -v + +# 3. 场景全通过后,跑压力测试 +RUN_INTEGRATION=1 pytest tests/e2e/test_e2e_stress.py -v + +# 4. 跑完后检查是否有残留 +curl -s http://localhost:8083/api/projects | python3 -c " +import sys, json +projs = json.load(sys.stdin) +e2e = [p['id'] for p in projs if p['id'].startswith('e2e-')] +print(f'e2e 残留: {len(e2e)} 个') if e2e else print('无残留 ✅') +" +``` + +## 测试数据清理 + +```bash +# 手动清理所有 e2e 残留 +cd ~/.sanguo_projects/sanguo_moziplus_v2/data +sqlite3 registry.db "DELETE FROM projects WHERE id LIKE 'e2e-%';" +rm -rf e2e-v27-* +``` + +## 三层测试对照 + +``` +单元测试(快,mock) → 验证逻辑正确性,随便跑不污染 +集成测试(中,tmp_path) → 验证 API + DB 交互,随便跑不污染 +E2E(慢,真实 Agent) → 验证完整链路,需要 RUN_INTEGRATION=1,测完要清理 +``` + +## 关键规则 + +1. **只有 E2E 会 spawn 真实 Agent**,单元和集成不会 +2. **不带 `RUN_INTEGRATION=1` 跑 `pytest` 是安全的**,E2E 全部 skip +3. **E2E 场景测试串行**,一个完成再下一个,失败要分析根因再继续 +4. **E2E 压力测试并行**,场景测试全通过后再跑 +5. **测试数据用 `e2e-` 前缀**,atexit 兜底清理,手动清理见上方