这是本节的多页打印视图。 .
测试
测试规划、e2e 场景清单与测试约定——质量保障的覆盖地图与走查底稿。
1 - QMTV 测试规划(Go 版,P0 底册)
回答移植需求②"基于现有项目先写单元测试——移植现有测试(如果有),或另写"。现状实测:冻结版零单测,仅 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 落地引入。
2 - QMTV E2E 测试约定
二十六期(2026-10-19)立册。对齐 pms e2e 约定骨架,按 QMTV 单库场景裁剪。 场景覆盖地图见 e2e-qmtv-场景清单.md。
§1 初始世界
- 环境:
bash scripts/dev/e2e/e2e-up.sh一键起——独立库qmtv_e2e(DROP/CREATE 即全量 reset)+ 端口:3301(与 dev :3300 三隔离:库/端口/产物文件名,可共存)+ 托管frontend/dist(每次 up 强制重建,永测当前 src)。停环境e2e-down.sh;快恢复(不重建库)e2e-seed.sh。 - 种子自检:
e2e-verify.sh六项(healthz / admin·demo·producer 三账号登录 / models-active / style-presets)——绿才能跑用例。 - 账号矩阵:admin@qmtv.com(管理员,credits 100000)/ demo@qmtv.com / producer@xingmang.cn——密码=seed 公开演示值,不入新密。API 造数的辅助账号一律
e2e-前缀 email;storageState 册(.auth/{admin,demo}.json)由 setup 项目真实 UI 登录一次产出,用例零登录(对抗 login 20/min 限流)。 - 确定性规则:未配置
model_endpoints→ 生成类全走内置 Mock 同步 done(无轮询等待、无外部超时);Mock 图像/视频字节含随机源——只断结构确定(卡片存在/URL 可达/台账行),绝不断素材内容。 - 预置种子:SQL seed(admin/demo+分销配置+计费 KV)+ Go seed(producer+示例任务链)。业务单据不进种子,一律 API 造数。
- 隔离与清理:用例各自造数各自收尾(集成侧 integCleanup 同纪律);失败不自愈——重跑前
e2e-up;连跑两轮必须间隔 reset(credits 水位会漂移)。
明令禁止
- 禁 sleep 等待 UI 条件——唯一合法等待面是 Playwright 自动等待/
expect.poll/waitForEvent/pollUntil。豁免两处(登记):①巡检类用例的路由间静置窗口(nav/admin 的waitForTimeout(400/1500)、snapshots 截图前waitForTimeout(800)——错误收集窗/渲染落定窗,非断言等待);②截图前networkidle。 - 禁 retry——config
retries: 0(pms flaky 规则:禁 retry 掩盖;修复优先序 改等待>改定位>改断言>最后才是 retry)。 - 禁断全局计数/绝对余额——流水断言用 total 相对面 + 最新行身份;余额用
assertBal恒等式(后端集成侧)。 - 禁触 qmtv_main / pms_ / sw_main*——e2e 只操作 qmtv_e2e 单库(远程 139 共享实例纪律平移)。
- SSE 面禁 networkidle——EventSource 长连接使 networkidle 永不触发;巡检用 load+双 rAF+静置窗口。
§2 可测性硬规则
- 断业务结果,不断文案细节:toast 只断关键短语(「拆解完成」「去字幕完成」);选择器优先 role/placeholder/既有稳定 class,不批量加 testid(触碰面爆炸);高频锚点按需单点补并在此登记。
- 失败留证:trace
retain-on-failure+ screenshotonly-on-failure→e2e/.artifacts/(gitignore)。 - 断言/截图分文件一行不共用(pms 硬规则):断言册
playwright.e2e.config.ts(testDir e2e,smoke 项目收assertion/*.spec.ts);截图册playwright.config.ts(只收snapshots.spec.ts)。 - API 侧错误信封直接抛(
e2e/lib/client.tsapiReq):非 2xx 抛响应体——静默吞错=测试说谎。 - 对话框断言用
waitForEvent('dialog')(once+变体捕获有竞态——auth.spec 负样本抓获);LoginView 错误走原生 alert,业务 confirm 各页分散(WorkbenchView 仅 repaint 空描述分支)——用例写前先读该页 submit 源码,勿凭笔记推 dialogs。
§3 运行手册
§4 flaky 处理规则
- 72h 内同一用例红 ≥2 次 → 摘出开单,不得带红合入;
- 7 天未修 → 删用例(场景清单「自动化?」列同步回落「待实现」);
- 关键用例落地必配负样本演练(涉及金额/回归锁/A1 教训面——改断言键名/路径必红才转正;A1 fixture 死键教训:键名错→锚死力失效)。巡检类(nav/admin 只读遍历)可豁免——harness 判死力由其它用例的有机红佐证(二十六期如实报告:admin.spec 无单独负样本,nav/auth/credits/dashboard/generation 五处有机红已证)。
§5 场景登记与回归锁
- 场景 ID 唯一(
E2E-<模块>-<序号>),ID 标注于 spec 文件头注释(用例名可不带前缀)——清单与 spec 双侧 grep 对账按场景 ID 级(「自动化?=是」的行必须有对应 ID 的 spec 文件,清单「现状」列登记 ✅ 文件名)。〔二十七期勘误:原「用例同名对账」与实际不符——ID 在头注释非用例名,对账实为场景 ID 级 9=9+文件级 ✅ 列。〕 - 缺陷修复优先「并入现有场景加断言」(回归锁),不新开用例——本仓
/review-planA 类「验收锚点」判死力机制直接挂此。 - 写链场景(导出 ZIP、充值审核、分销提现等)先登清单「待实现」行,后续期次升格。
3 - QMTV E2E 场景清单(覆盖地图)
行格式:场景 ID 唯一;「自动化?=是」行与
frontend/e2e/assertion/*.spec.ts按场景 ID 级对账(清单 ID ↔ spec 文件头注释 ID+「现状」列 ✅ 文件名,与测试约定 §5 同口径;二十七期勘误:原「用例同名」与实情不符——用例 ID 在文件头注释非用例名)。 「FSD 功能 ID」列=场景↔功能规格双向对账锚(三十一期回填)——指向prd/fsd-qmtv/各册F<m>.<nn>节;横切场景(积分/导航/截图)无单册归属标「横切」。 二十六期首批冒烟 8 场景全走 Mock 同步面(避开 SSE 依赖与长轮询);写链场景登「待实现」后续升格。
| 场景ID | 场景名 | 模块/页面 | 前置种子 | 主干路径(系统视角) | 关键断言 | 冒烟? | 自动化? | FSD 功能 ID | 现状 |
|---|---|---|---|---|---|---|---|---|---|
| E2E-AUTH-01 | 登录/守卫/登出 | auth/LoginView+App 导航+router guard | 三账号 seed | 错密码 alert→admin 登录跳首页→未登录访 /dashboard 重定向→demo 无管理后台入口且直访 /admin 顶回→admin 可达 /admin 并登出回 /login | alert 文案「邮箱或密码错误」;URL 断言×4;权限分层入口可见性 | 是 | 是 | F1.01~F1.09(登录 F1.02) | ✅ auth.spec.ts |
| E2E-DASH-01 | 工作台拆解提交 | dashboard/DashboardView | admin 零任务 | POST /tasks/v2(Mock 同步)→toast→列表 invalidate | toast「拆解完成」;任务卡镜数>0(A1 回归锁:wire=驼峰 shotCount,误读蛇形恒 0 必红) | 是 | 是 | F2.03(V2 拆解)+F2.01(列表) | ✅ dashboard.spec.ts |
| E2E-GEN-01 | 独立图片生成 | independent-tools 图片 tab | admin 登录 | POST /images/generate(Mock 同步 done) | .img-card 即现且含提交提示词 | 是 | 是 | F3.08(图片素材) | ✅ generation.spec.ts |
| E2E-GEN-02 | 工作台工具提交 | workbench/WorkbenchView | API 造 standalone video(standalone:true 必传) | 选工具→选成片→提交→Mock 同步 done | toast「去字幕完成」(去字幕无 confirm——confirm 仅 repaint 空描述分支) | 是 | 是 | F11.01+F11.02(提交+轮询) | ✅ generation.spec.ts |
| E2E-CRD-01 | 积分流水闭环 | credits/CreditsView | admin 登录 | API 造图片生成→台账入账 | total 相对 +1;最新行含「独立图片生成(-10)」(不断首页行数——分页满页恒等碎) | 是 | 是 | 横切(总则 §2.3;台账 F1.06) | ✅ credits.spec.ts |
| E2E-ADM-01 | 管理端只读巡检 | admin/AdminView | seed 三账号 | 概览/用户管理/任务审计/剧本管理四 tab 遍历 | .stat≥5;用户行≥3;tab 面板渲染;零 5xx 零错误 toast | 是 | 是 | F12.01+F12.02(跨 m01/m02/m09 tab 注记) | ✅ admin.spec.ts |
| E2E-NAV-01 | 全站只读巡检 | 20 路由全页遍历 | admin storageState | 逐页 goto+load+双 rAF+静置窗 | 零未捕获 console error / 零 /api 5xx / 零 /api 网络失败(已抓获 spark 缺口) | 是 | 是 | 横切(全站路由) | ✅ nav.spec.ts |
| E2E-SPK-01 | 火花计划加入链 | spark/SparkView | admin 未加入(e2e-up 后初态) | UI join→me invalidate | 「已加入」标签现;API me.joined=true;重跑容错(残留轮直断投影面) | 是 | 是 | F13.01 | ✅ spark.spec.ts |
| E2E-SNAP-01 | 截图管线自检 | snapshots.spec.ts | admin storageState | 全站 24 图(公开 3+登录态 21;dashboard 填样例文本不提交;/export/:taskId 参数页豁免截列表态)落 docs/manual/images/ | PNG 字节非空+零重复字节(26 期四图→27 期 24 图扩容;settle 信号驱动 waitForFunction,公开页固定短 settle) | 是 | 是 | 横切(截图管线) | ✅ snapshots.spec.ts |
| E2E-SUB-01 | 投稿→过审→剧本超市上架 | studio+admin 投稿审核 | demo 投稿+admin 审 | POST submissions→admin approve→library 可见 | 状态机翻转+跨用户可见 | 是 | 待实现 | F9.03+F9.07(投稿+审核上架) | 二十七期候选 |
| E2E-RCH-01 | 充值凭证→审核入账 | recharge 双端 | demo 充值申请+admin 审 | POST recharge→upload 凭证→approve→余额+台账 | 金额入账恒等式 | 是 | 待实现 | F8.01~F8.03 | 二十七期候选 |
| E2E-EXP-01 | 成片导出 ZIP 下载 | export/ExportView | 已有 done 分镜 | GET-or-POST 导出编排→2s 轮询→ZIP 下载 | ZIP 魔数+分镜数 | 是 | 待实现 | F4.01(导出编排) | 后续候选 |
| E2E-WD-01 | 分销提现申请与审核 | distribution | 分销关系+佣金余额 | 提现申请→admin 审→余额划转 | 双向台账恒等式 | 是 | 待实现 | F7.03+F7.06(申请+审核) | 后续候选 |
| E2E-DIR-01 | 导演工作台分集拆解 | director3d | admin 登录 | 建项目→拆分集→分镜图生成 | director_shots 回填 | 是 | 待实现 | F10.01~F10.06(项目/分集/分镜图) | 后续候选 |