# QMTV 测试规划（Go 版，P0 底册）

LLMS 索引： [llms.txt](/llms.txt)

---

> 回答移植需求②"基于现有项目先写单元测试——移植现有测试（如果有），或另写"。现状实测：冻结版**零单测**，仅 4 个 API 冒烟脚本（verify_*.js）覆盖 60/239 端点。结论：**以 TDD 另写为主（pms 范式），verify 断言移植为集成冒烟底册，e2e 骨架按 pms 约定立**。

## 1. 分层测试范式（对齐 pms backend）

| 层 | 手段 | 纪律 |
|----|------|------|
| repo 层 | **sqlmock**（DATA-DOG/go-sqlmock）；`newMockDB` 4 行 helper 就地定义，无共享 testutil | 断言 SQL 形状 + `ExpectationsWereMet`；结尾必校验 |
| service 层 | **手写 fake repo**（map 内存副本）；关键纪律=**fake 忠实 gorp 语义**（Insert 后 version=原值+1 等回写行为必须模拟，防掩盖差一缺陷） | 纯函数尽量抽出独立测（计费/解析器/提示词组装） |
| handler 层 | 不测（薄层，零业务逻辑——域包四文件铁律保证） | 装配冒烟在 main_test.go |
| 守卫 | cmd/server 三件（not_null/pointer_field/status_table），schema 六原则机器守卫 | 负样本演练留档 TECH.md §9 |
| 集成冒烟 | `//go:build integration` 标签真库用例（对齐 pms test/smoke_test.go；MySQL 不可用自动 skip）+ verify 移植断言 | dev-up 环境跑 |
| 全局 | `go test ./... -race -count=1` 纯 mock 不连外部服务 | CI 缺省档卡点 |

## 2. 分域单测规划（先红后绿，TDD 顺序=P 期次）

| 域 | 期 | 必测纯函数/场景（首批） |
|----|----|------------------------|
| auth | P1 | scrypt 往返（已有）、JWT 双格式（已有）、refresh 轮换状态机（签发→轮换→旧 token 拒→过期拒→改密全撤销）、注册送积分+邀请返佣、限流窗口边界 —— **P1 已落地**（service 11 场景 + repo sqlmock 7 + jwtsecret 3 + main_test 装配 4 + integration 全链/C8 互操作；限流 4 场景见 gateway 包） |
| credits | P1 | CAS 扣款成功/余额不足 402/版本冲突重试/退款 refunded 防重/balance_after 台账一致性/COSTS×settings 双层计费价 —— **P1 已落地**（billing 6 + repo sqlmock 6 + service fake 6 + integration 并发不超扣/台账对账/零台账）；差异收口（PRD v1.3）：CAS 谓词仅 credits>=? 下无版本冲突路径，RunWithRetry 定稿不引入；退款防重=credits.Refund 唯一口（F9），P2 W7 落地 |
| task | P2 | Mock 规则拆解（场次切分/人名提取/景别轮转——preprocess.js 逐规则移植对拍）、parser.parseSplit 宽容解析（60 镜上限/img 1200 字）、LLM 拆解失败回退链 —— **P2 执行中**（2026-10-18 立项） |
| generation | P2 | ratio→尺寸映射、videoCost(secs)、providers 三响应形态分发、轮询状态词判定、Mock SVG/WAV 字节头 —— **P2 执行中** |
| export | P2 | 导出积分×段数、export_tasks 全链（期次随 TECH 域包表 P2，v1.3 对齐） |
| director/fusion/workbench | P3 | 双表通路 _tbl 路由（Go videoSmart 显式表参数，P2 期初定型）、队列 recoverQueue、审片双入口 |
| billing-admin | P4 | 充值到账+两级返佣、提现 7 态状态机、白名单键过滤（credit-settings PUT） |

## 3. verify_*.js 断言移植矩阵（约 60 端点 → Go 集成冒烟）

现有脚本逐断言移植为 Go 集成测试（`integration` 标签，dev-up 环境执行；脚本本身保留在冻结区不动）。「可测期次」= 该端点 Go 实现落地期。端点数为**约数（唯一路径口径）**：分项 ~28+~20+~6+~9 含同端点多场景重复计数，去重后约 60。

| 源脚本 | 断言场景 | 端点数 | 可测期次 | Go 冒烟形态 |
|--------|---------|-------|---------|------------|
| verify_v14.js | 火花 join/me/阶梯；工作台三工具+列表；经典审片+回读；导演项目→分镜→导演审片+资产队列挂起；组织申请→审批→邀请→加入→**非 owner 改角色拒**→项目共享→成员可见 | ~28 | P3（组织面 P4） | Go httptest 或真库 curl 链 |
| verify_v17.js | 企业看板/trend/双排行；writers 排序+主页；showcase 发布/撤下；全站搜索；剧本库新字段；素材夹+10GB 容量+assign；**非 owner 建组拒**；错密码改邮箱拒 | ~20 | P4 | 同上 |
| verify_eval.js | evaluations/config；txt 上传；**GBK 非法字节回退不崩**；深度评估 stage 推进轮询；报告下载含逐集证据 | ~6 | P3 | 同上（stage 推进用 pollUntil） |
| verify_lib.js | genres 配置；种子幂等回填；五维筛选；详情目录；rating/new 排序；管理端 CRUD+用户端 404 | ~9 | P3 | 同上 |
| **新增（脚本空白，各期验收补）** | 登录/refresh 真轮换/改密；扣款 402/退款防重；拆解 v2 双引擎+回退；视频 v2 按秒计费；SSE 五类事件（Go 侧 client 断言帧格式）；4 个 ZIP 端点结构；充值→审核→返佣→提现全链；模型接入 18 端点 | ~179 | 随 P1~P4 | 每期验收新增集成用例 |

## 4. E2E 约定骨架（正式版 P5，按 pms docs/test 三文档体系）

- **初始世界**：独立库 `qmtv_e2e`（dev-up 变体建库导 full+seed）；账号矩阵=seed 三账号+按需 API 注册；**业务单据不进种子，一律 API 造数**（防绕过状态机）。
- **外部 API 零真实调用（用户指令 2026-10-17，instructions.txt）**：e2e/集成测试**局限在本系统内，外部 API 调用会引起费用——全部 mock**。LLM/图像/视频供应商一律走 Mock 通道（测试环境不配 model_endpoints 的 api_key，或显式 provider_routing=mock）；网络出口断言（providers 适配层的真实 HTTP 调用）用 httptest 本地假服务器验证协议形状，绝不打真实供应商；CI 环境保持零 Key（`llm.isAvailable()==false` 全站 Mock 路径），真实供应商连通性只允许人工在管理后台用「测试连接」单次验证。
- **确定性**：时间用相对量；金额固定值；禁按自增 id 断言（qmtv 全字符串 ID 天然满足）。
- **隔离**：`e2e-reset`（DROP/CREATE+导入）/`e2e-seed`（快恢复）；失败不自愈必须 reset；连跑两轮间隔 reset。
- **明令禁止**：禁 sleep 等事件链（一律 pollUntil，超时 20s——评估 stage 推进/视频轮询场景）；禁 retry；5xx 直接抛响应体。
- **场景登记**：`docs/test/e2e-qmtv-场景清单.md` 行格式对齐 pms（场景ID E2E-XXX-NN｜FSD 功能 ID｜主干路径｜关键断言｜现状）；缺陷修复覆盖优先并入现有场景加断言。
- **Playwright 引入与否**：P5 决策——前端冻结的前提下，API-first 断言册已覆盖回归需求；截图册（操作手册配图）可单独用 Playwright 走真 UI，不与断言册共用一行代码。（**二十六期已落地**：前端演进后 Playwright 双配置入位——断言册 11 用例〔auth 4/dashboard/generation 2/credits/admin/nav/spark；含 setup 册 14〕 + 截图管线，约定见 docs/test/e2e-测试约定.md；本条 P5「前端冻结」前提已随 TS 演进裁决失效，双配置即终态。二十七期勘误：二十五/二十六期宣称「13 用例」系计数漂移，11 为亲数权威口径。）

## 5. CI 闸门（scripts/ci.sh，已落地）

| 档 | 内容 | 时长 |
|----|------|------|
| --fast | build+vet+check_consistency+**冻结契约守卫（frozen_contract_check）**+守卫三件 | <1min |
| 缺省 | +全量 `go test -race -count=1` | ~2min |
| --with-env | +dev-up+healthz+**登录真断言+refresh 轮换断言（新旧 RT 不同/旧复刷 401）+query token 兜底** | +1min |
| --e2e | =--with-env 全部 + e2e 环境（qmtv_e2e/:3301/frontend/dist 托管）+ Playwright 断言册——**显式 opt-in**，浏览器二进制不进日常闸门（二十六期第四档） | +2min |

JUnit 双断言（场景总数≠期望也阻断）随 P5 e2e 落地引入。

---

反链：

- [测试](/qmtv/test/)
