tdd-inspection-report.md 22 KB

CFC 测试与代码审查巡检报告(滚动 · 最新一轮 · 第 19 次)

  • 巡检时间:2026-11-03 00:27–(GMT+8)
  • 执行主体:软件测试专家团 · 主理人(测试架构师陆谨)|编排角色:测试(--role 测试,只读)
  • 执行档:review(离线只读)|未跑 mvn test / playwright / pytest,未联网,未派发 opencode,未 commit / push
  • 面向对象:CFC 全项目(d:/cfc,data_ref=origin/cfclub)
  • 去重声明:docs/tdd/test/ 下最新兄弟产物为 automation-run-2026-11-02-2350.md(11-03 无同级产物),本轮已重扫;不重复生成 run 文件,只做增量取证 + 重写本滚动报告

一、历史审查记录

轮次 时间 结论 遗留缺口(本轮是否改善)
#16 11-02 21:37 不通过 仓库 844 MiB、提交噪音 67%——均未修(65.3%)
#17 11-02 22:44 不通过 3 影子测试未入库——部分改善(1/3 已入库)
#18 11-02 23:54 不通过 12 条门禁 0 全达成;P24 环境 502、P25 业务码未分型——均未修
#19(本轮) 11-03 00:27 仍不通过(2 项实质正向 / 1 项严重倒退) 新增 P26 台账证据销毁、P27 构建自证不可追溯
  • 本对象非首次审查(连续第 19 轮)。历史结论仅作对照,本轮全部数字重新取证。
  • 「Maven 环境不可得」旧判定持续为误判,本轮第 8 次独立复核:C:/Program Files/JetBrains/IntelliJ IDEA 2025.2.5/plugins/maven/lib/maven3/bin/mvn.cmd 存在,java 1.8.0_25 在位,command -v mvn 仍 not in PATH。

二、项目画像(本轮复核,结构无变化)

维度 事实
业务定位 家庭教育成长平台(浠艾福 XAF):家庭成员 / 五维能量 / 测评订单 / 健康报告 / 商城 / AI 对话(AI 教练已有付费门禁)
技术栈 Spring Boot 2.7.18 + MyBatis-Plus(9082)· uni-app 小程序 · Vue2 管理端(8082)· FastAPI+LangGraph(9000)· 独立商城(8888)
关键路径 登录鉴权(JWT)→ 家庭成员 → 测评订单支付 → 健康报告上传解析 → 能量发放 → 内容审核 → AI 教练(会员门禁)
测试资产 196 Java 测试文件 / 1464 @Test(其中 2 文件 12 例仍仅在工作区)|410 Playwright|47 pytest|729 结构化 md 用例|9 场景文件|合计 2650
质量目标 可重复执行的后端套件全绿 + 冒烟收敛 + CI 阻断 + 覆盖 ≥30% + P0 用例自动化 100%
环境事实 Maven 3.9.9 可得未入 PATH;cfc-backend/target/ mtime 停在 11-01 20:55、target/test-classes 停在 11-01 20:54 → 本地自 11-01 起零构建
风险点 覆盖 10.59% · 无 CI · 13 条既有红灯 · 冒烟指标不可信 · 关键缺陷台账被删 · 仓库 844.34 MiB · 前端零回归护栏

本轮增量事实(23:54 → 00:27,共 4 次提交)

提交 时间 性质
faf3ca174 23:45 测试修复:DanAssessmentControllerGetActiveMaterialTest 90 行/3 @Test 入库,修 setName→setTitle 编译阻断
73bfa3321 00:03 自动 bump 版本
bb4040057 00:05 前端登录页品牌区重构(232 行)+ test_blockers.md −40 行(见 P26)
1ddaedcfe 00:10 冒烟 00:05(fix=0 reg=1)

git rev-list origin/cfclub...HEAD = 0/0(HEAD 与远端同步)。


三、20 类测试覆盖矩阵(三态 · 逐类证据)

# 测试类型 状态 证据 / 说明
1 单元测试 已发现 196 文件 / 1464 @Test(↑1463);205/1936 handler(10.59%)被命中
2 测试覆盖率 未发现(工具) 无 JaCoCo / Cobertura 配置与报告;仅静态 handler 命中率
3 变异测试 未发现 无 PIT / Stryker 配置或产物
4 契约测试 已发现(轻量) tests/e2e/api/*.spec.js 做应答结构断言;无 Pact 类工具
5 集成测试 已发现(局部) *Integration* 类 + 4de8cb16a/1e644bffe 自带测试;本轮 faf3ca174 为 standalone MockMvc 单测(非集成)
6 接口 API 测试 已发现 545 端点冒烟(00:05 轮次)+ API e2e(口径存疑,见 P11)
7 系统 / 端到端 已发现(受限) 279 条 DOM 型 E2E 受 CFC-ENV-001 阻塞;bb4040057 前端 232 行改动零用例验证
8 验收 UAT 已发现(文档) docs/REVIEW_SYSTEM_ACCEPTANCE_白樾.md 等仍 untracked
9 BDD 规格 未发现 无 .feature / Cucumber / behave
10 冒烟测试 已发现 11-03 已跑 2 次(最新 00:05)
11 回归测试 已发现(弱) 依赖同一冒烟脚本;tsv 双文件 md5 相同(e2dd2f3e…/91546B),prev.tsv 仍 untracked(P8 未修)
12 探索性测试 未发现 无 charter / 会话记录
13 性能测试 已发现(轻量) nonfunc-perf-compat.spec.js 5 例;无压测基线
14 可靠性测试 已发现(被动) 仅由 11-02 23:40 整站 502 等事件被动暴露;无主动故障注入
15 安全测试 已发现(证据退化) nonfunc-security.spec.js 11 例仍在;但 R5/R6 缺陷行已随 test_blockers.md 被删(P26),跟踪载体丢失
16 兼容性测试 已发现(轻量) nonfunc-perf-compat.spec.js 含兼容断言;无设备矩阵
17 可用性测试 未发现 无真实用户可用性证据
18 无障碍测试 未发现 无 axe / WCAG 扫描
19 QA 流程 部分发现(倒退) TDD 状态机(2 键停 RED)+ 冒烟脚本;缺陷台账出现「删除即闭环」反模式
20 质量度量 部分发现 有指标采集,但 fix/reg 无因果(P15 第 8 度)、E2E 口径两套(P11)

覆盖分布:covered=16|partial=72|uncovered=268|no-handler=1(共 357 控制器)。


四、测试方案(本轮)

  • 目标:判定 #18 遗留问题是否改善,并识别 23:54 后 4 次提交引入的新风险
  • 范围:全项目(20 类全覆盖口径);重点 = 新入库测试的真实性、台账完整性、冒烟指标可信度
  • 排除项:dan/danshop、cfc-langgraph(无变更)
  • 优先级:P0=可执行性/证据完整性;P1=指标可信度;P2=工程卫生

五、执行档

项 值
档位 review(离线只读)
已执行 discover_tests.py、test_inventory.py、git 只读取证、产物解析(surefire XML / tsv md5 / trend log / .last-run.json)、源码只读复核
未执行 mvn test(可得/未授权)、playwright、pytest、压测(未联网授权)、八域深审派发
结论影响 未实测维度一律标注「未实测」,不写成通过

六、覆盖缺口清单

# 缺口类型 现状 风险 建议测试设计 优先级 闭环方式
G1 单元覆盖 205/1936 = 10.59% 268 控制器零覆盖 按未覆盖 handler 数排序,先补 AdminController(65)、DanAssessmentController(29) P0 JaCoCo 行覆盖 ≥30%
G2 可执行性 1452 条已跟踪 @Test 中约 1315 条从未执行(surefire 仅 17 XML,停 11-02 08:39) 套件实际可用性未知 授权 mvn -o -DskipITs test 全量跑一次并留存 surefire P0 全量 surefire 产物入库
G3 缺陷台账完整性 test_blockers.md 130→90 行,R5/R6/§7 全删 安全缺陷失去跟踪载体 从 git show bb4040057^:docs/tdd/test/test_blockers.md 恢复并加删改评审 P0 R5/R6/§7 恢复入库
G4 构建证据 target/ 停在 11-01 20:55,faf3ca174 自述的 mvn 运行零产物 「已修复」不可复核 构建产物/日志作为提交附件或 CI artifact P0 一次可复现的 mvn test-compile 记录
G5 回归可判定 fix/reg 把连接抖动当因果(P15 八度复现) 冒烟结论无意义 CONN_ERR 三次重试 + 连续 2 轮稳定才计数;reg>0 非 0 退出 P0 连续两轮 fixed>0 且人工确认
G6 E2E 口径 报告「51 通过/3 failed/3 skipped」=57 例 vs §7「59/7/3」=69 例,且 §7 已被删 两套数字、分母消失 统一 expected/unexpected 口径,test.fail() 计数单列 P1 单一数据源 + 口径说明入报告
G7 P0 用例自动化 79 条 P0 文档用例 100% 待自动化 主链路无机器护栏 按模块批量转 Playwright API spec P1 P0 自动化 100%
G8 CI 门禁 无 .github/workflows/.gitlab-ci.yml/Jenkinsfile 红灯不阻断合并 最小流水线:编译 + 单测 + 冒烟 P1 PR 红灯阻断
G9 新增测试可追溯 2 文件 12 例仍 ??(HealthReport 5 / SupplyTeam 7) 账实不符 git add 入库并登记执行状态 P1 工作区干净 + 执行记录
G10 仓库可 CI 化 844.34 MiB;.wt-* 三目录常驻 ?? clone 成本高 大文件移出 + .gitignore 加 .wt-*/ P2 pack < 200 MiB
G11 前端零护栏 bb4040057 232 行前端改动无任何用例 样式/交互回归不可见 部署含前端的测试环境 + DOM 用例解阻 P2 至少 1 个前端冒烟
G12 环境可靠性 11-02 23:40 整站 502(406 行 http=502),两天 4 次 巡检结论不可靠 采集前健康探针 + INVALID 告警 P1 探针前置 + 告警通道

七、域结论表

审查维度 负责专家 结论 关键证据
单元·组件级 苏雅 未通过 205/1936;新入库 3 例设计合理但无执行产物
集成·接口级 柯砚 未通过 545 端点 45%;E2E 口径两套且分母被删
系统·验收级 白樾 未通过 279 DOM 用例阻塞;UAT 文档 untracked
测试保障级 闻朔 未通过 冒烟同日同结果;回归基线未版本化
性能·可靠性 骆骋 待核实 无压测授权;可靠性仅被动暴露
安全 关屿 未通过(退化) R5/R6 行被删;Result.error 恒 500 未修
兼容·体验 阮清 待核实 无设备矩阵;无无障碍扫描
流程·度量·代码 何序 未通过 台账删除即「闭环」;提交噪音 65.3%

说明:本轮 8 域中 5 域未派发深审(无新增测试资产变化 + review 档),以上为主理人基于只读取证的门禁判定,非域专家署名结论;域报告落盘仍为 3/8。


八、五要素问题清单

P26|关键缺陷台账被删除(本轮最严重)

  1. 问题描述:bb4040057(00:05,标题为 feat(ui): 登录页品牌区重构 + TDD 台账更新)将 docs/tdd/test/test_blockers.md 从 130 行删至 90 行(−40 / +1),提交说明未提及删除。
  2. 测试 bug 点:docs/tdd/test/test_blockers.md 当前 grep -nE "R5|R6|^## 7" 零命中;被删内容包括 R5(POST /api/admin-auth/login 未鉴权返 500)、R6(报告上传无 MIME/类型校验)、§7.1 七条真实 unexpected 缺陷表(F1 butler envelope、F2 commission 400 等)、§7.3 成熟度结论、§7.4 下一步。
  3. 最优修改方案:git show bb4040057^:docs/tdd/test/test_blockers.md > docs/tdd/test/test_blockers.md 恢复;对 docs/tdd/test/*.md 单次删除超阈值(如 −20 行)时,要求提交说明写明「删除原因 + 迁移去向」。
  4. 修改目的:保住唯一记录 R5/R6 安全缺陷与 7 条真实 E2E 缺陷的载体,使安全与回归缺口可持续跟踪、可复评。
  5. 闭环判据:恢复后文件行数 ≥130 且 R5/R6/§7.1 表格逐行可见;下次巡检该文件 git diff 为 0 或仅新增。

P27|「已修复」自证无任何构建产物

  1. 问题描述:faf3ca174 自述「mvn test-compile BUILD SUCCESS(194 测试源文件);mvn test -Dtest=... 3 用例全绿」,但本地无任何产物佐证。
  2. 测试 bug 点:cfc-backend/target/ mtime = 11-01 20:55、cfc-backend/target/test-classes = 11-01 20:54;全仓 find -name "TEST-*GetActiveMaterial*" 零结果;三处 surefire 目录最新分别为 11-02 08:39 / 11-02 00:25 / 10-25 22:32。
  3. 最优修改方案:构建/测试输出(surefire XML 或 mvn -o test-compile 日志尾部)作为提交附件或 CI artifact 留存;至少在本机 cfc-backend/ 复跑一次并保留 target/surefire-reports/TEST-*.xml。
  4. 修改目的:让「编译阻断已修复」这一关键结论可被独立复核,避免后续巡检继续按「套件不可执行」判定。
  5. 闭环判据:存在 TEST-*DanAssessmentControllerGetActiveMaterialTest.xml 且 tests="3" failures="0" errors="0";target/ mtime 晚于 faf3ca174 提交时间。

P28|Maven 可得但仍无一次全量执行(延续 G2)

  1. 问题描述:1452 条已跟踪 @Test 中约 1315 条从未执行,surefire 仍停 11-02 08:39 的 17 个 XML(13 红)。
  2. 测试 bug 点:cfc-backend/target/surefire-reports/*.xml = 17 个,最新 AuthControllerTest.xml 08:39;13 红(8 fail + 5 error)未变。
  3. 最优修改方案:授权执行 mvn -o -DskipITs test(离线、~/.m2 已有依赖),采集全量 surefire,逐条定位新红。
  4. 修改目的:把「套件是否可执行、红了多少」从猜测变为实测,为 G2/G4 提供基线。
  5. 闭环判据:surefire XML 数 ≈ 测试类数(194+),且红/绿清单入库。

P15(第 8 度复现)|fix/reg 把连接抖动当代码因果

  1. 问题描述:00:05 记 reg=1,唯一来源 POST /api/user/portrait/regenerate BIZ_OK→CONN_ERR;而 23:48 该端点刚被记为 fix=1(CONN_ERR→BIZ_OK)。12 分钟内同一端点 ERR→OK→ERR 往返两次,期间无 portrait 相关代码变更。
  2. 测试 bug 点:interface_test_trend.log 末行 20261103_000520 … fixed=0 regressed=1;git show 1ddaedcfe -- interface_test_report.tsv 差异仅该端点一行 200/BIZ_OK → -1/CONN_ERR。
  3. 最优修改方案:CONN_ERR 单端点连续 3 次重试后再定级;同一端点同日内往返 ≥2 次标记 FLAKY 而非 fix/reg;reg>0 时脚本非 0 退出。
  4. 修改目的:使回归指标反映代码变化而非网络抖动,恢复冒烟结论的决策价值。
  5. 闭环判据:连续两轮 fixed>0 且经人工确认对应真实代码变更;portrait/regenerate 不再单独产生 fix/reg。

P8(未修)|回归基线未版本化

  1. 问题描述:interface_test_prev.tsv 与 interface_test_report.tsv 字节级相同(md5 e2dd2f3ef6ad26187210437faed14d8d,各 91546B),但 prev.tsv 为 untracked,基线不可版本化。
  2. 测试 bug 点:git status --porcelain 含 ?? interface_test_prev.tsv;比较逻辑本身正常(cp 在比对之后),缺陷在于基线来源为本地文件。
  3. 最优修改方案:脚本基线改 git show HEAD:interface_test_report.tsv > /tmp/prev.tsv,删除对本地 prev.tsv 的依赖。
  4. 修改目的:全新克隆/CI 环境下 fix/reg 仍可复现,避免「基线只在本机成立」。
  5. 闭环判据:脚本中 interface_test_prev.tsv 引用数为 0,且 CI 跑一轮 fix/reg 与本地一致。

P13(未修)|Result.error() 恒 500 污染全部分型

  1. 问题描述:cfc-backend/src/main/java/com/etotem/cfc/common/Result.java:37-39 仍 setCode(500),参数缺失/无权限一律伪装成服务器错误。
  2. 测试 bug 点:Result.java 第 37–39 行 error(String) 硬编码 500;冒烟 SERVER_ERR_COUNT=0 恒成立属假安全信号。
  3. 最优修改方案:新增 badRequest(400) / forbidden(403) / notFound(404),新代码先用;冒烟按 code + message 分桶。
  4. 修改目的:让「被拒」与「崩了」可区分,安全断言才有意义(R5 类缺陷正因此被误判)。
  5. 闭环判据:error() 分支不再写 500;冒烟 SERVER_ERR 能非 0 并对应真实 5xx。

P16(未修)|扫描器 handler 路径等值匹配

  1. 问题描述:discover_tests.py:391 仍用 p in hit_paths 做等值匹配(handler 存相对路径 /report/create,测试写 /api/health/report/create)。
  2. 测试 bug 点:discover_tests.py 第 391 行 ok_http = p in hit_paths;已量化影响上限 +9 handler(203→212 ≈ 11.0%)。
  3. 最优修改方案:改后缀匹配 any(h.endswith(p) for h in hit_paths),并处理同名类(controller/ai/ButlerController vs controller/butler/ButlerController)用 FQN 作键。
  4. 修改目的:覆盖数字反映真实测试量,避免「补了测试但指标不动」的错觉。
  5. 闭环判据:修后覆盖分子上升且 discovery.md 的 covered 明细可逐条追溯。

P9(未修)|.last-run.json 自相矛盾

  1. 问题描述:tests/test-results/.last-run.json 仍 {"status":"failed","failedTests":[]},与「51 通过」的报告冲突,且该文件被 git 跟踪。
  2. 测试 bug 点:该文件当前 status=failed 而 failedTests 为空数组;git status 显示为 M。
  3. 最优修改方案:Playwright 侧在 status=failed 时必须写入失败用例名;为空则视为采集异常,不产出报告。
  4. 修改目的:让 .last-run.json 可作为「本轮是否真跑过」的可信凭证。
  5. 闭环判据:status 与 failedTests 长度逻辑一致(failed ⇒ 非空)。

P17(部分闭环)|影子测试入库进度

  1. 问题描述:3 个未入库测试中,DanAssessmentControllerGetActiveMaterialTest 已于 23:45 入库(3 @Test,standalone MockMvc;已独立核验 AssessmentMaterial 确无 name 字段、只有 title,修复主张成立);其余 2 个(HealthReport 5 例、SupplyTeam 7 例)仍 ??。
  2. 测试 bug 点:git status --porcelain 含 ?? cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerCreateReportTest.java 与 ?? .../admin/SupplyTeamControllerInviteTest.java。
  3. 最优修改方案:两个文件 git add 入库;入库前各自 mvn test-compile 验证(避免重现 faf3ca174 修过的编译阻断)。
  4. 修改目的:消除「账实不符」,让覆盖数字与 git 跟踪一致。
  5. 闭环判据:git ls-files cfc-backend/src/test/java | wc -l = 196,工作区无 ?? src/test。

P11(未修)|E2E 口径两套且分母已消失

  1. 问题描述:冒烟报告称「API e2e 51 通过 / 3 failed / 3 skipped」=57 例,而原 §7 全量口径为 expected 59 / unexpected 7 / skipped 3 = 69 例;本轮 §7 随台账被删,69 例这一分母已无从复核。
  2. 测试 bug 点:INTERFACE_TEST_REPORT.md「API e2e 本轮 51 通过 / 3 failed / 3 skipped」;docs/tdd/test/test_blockers.md 已无 §7。
  3. 最优修改方案:test.fail() 不计入 passed,单列 expected-fail;报告固定输出 total/expected/unexpected/skipped 四元组,由脚本从 .last-run.json 直接生成。
  4. 修改目的:同一套用例只有一个数字,避免「57 vs 69」不可对账。
  5. 闭环判据:报告四元组之和 = 用例总数,且与 .last-run.json 逐项一致。

九、门禁结论

结论:不通过(12 条门槛 0 全达成;G9 部分改善,G3/G4 属新恶化)

门禁 判据 本轮状态
G1 可执行环境 Maven + JDK 可用且已授权执行 部分(工具在位,未授权执行)
G2 后端套件全绿 全量 surefire 无红 ✗(1315 条从未执行)
G3 缺陷台账完整 R5/R6/§7 在库 ✗ 倒退(被删 40 行)
G4 构建证据可追溯 有产物佐证「已修复」 ✗ 新增
G5 覆盖 ≥30% JaCoCo 行覆盖 ✗(10.59%,口径为静态命中)
G6 冒烟收敛 连续两轮 fixed>0 且人工确认 ✗(fix/reg 无因果)
G7 安全 11/11 nonfunc-security 全绿 ✗(R5/R6 载体已失)
G8 指标可信 fix/reg + E2E 口径单一 ✗
G9 新增测试可追溯 工作区无 ?? src/test 部分(1/3 已入库)
G10 仓库可 CI 化 pack < 200 MiB ✗(844.34 MiB)
G11 P0 自动化 79 条 P0 100% ✗(0%)
G12 CI 阻断 PR 红灯阻断 ✗(无 CI)

本轮 2 项实质正向(不计入门禁达成,但应记录)

  1. 影子测试首次入库且修了真实编译阻断:faf3ca174 把 AssessmentMaterial.setName 改为 setTitle。经独立复核,cfc-backend/src/main/java/com/etotem/cfc/entity/AssessmentMaterial.java 字段为 id/title/content/coverImage/status/createdAt/updatedAt,确无 name → 该编译错误成立,且说明「一个测试文件编译失败会让整批 1451 例全部不执行」,这是解释 08:39 后无 surefire 的合理机制(但本次运行本身无产物,见 P27)。
  2. 新入库测试设计质量良好:standalone MockMvc + mock AssessmentService,无 Spring 上下文、无 DB,可在 CI 离线跑;与 AIChatControllerGateTest 一起构成「可离线、可重复」单测模板。

最快翻盘顺序(按性价比)

  1. 恢复 test_blockers.md(1 条命令,止损最严重倒退)
  2. 授权 mvn -o -DskipITs test 跑一次全量并留存 surefire(同时闭环 G2/G4)
  3. git add 剩余 2 个测试文件(12 例)
  4. 修 Result.error() 分型 + discover_tests.py 前缀匹配(各数行)
  5. 冒烟脚本:CONN_ERR 重试 + 基线改 git show HEAD:interface_test_report.tsv
  6. 建最小 CI(编译 + 单测 + 冒烟)

十、未实测项(如实标注)

  • 未跑 mvn test(Maven 3.9.9 可得、未入 PATH、未授权)、playwright、pytest。
  • 无 JaCoCo:10.59% 为静态 handler 命中率,非行覆盖率。
  • 压测未授权联网:性能维度仅 nonfunc-perf-compat.spec.js 5 例接口级轻量断言,无基线、无并发。
  • 可靠性主动验证未执行:11-02 23:40 整站 502 为被动观测,非故障注入结果。
  • 八域深审未派发:5/8 域无落盘报告,结论标「待核实」。
  • faf3ca174 所称「3 用例全绿」未独立复现(无 surefire 产物)。
  • bb4040057 前端 232 行重构的视觉效果未验证(无前端环境)。
  • interface_test_prev.tsv 是否曾入库未追溯(当前 untracked)。
  • P0 计数口径:以工具台账为准 79 条 P0(100% 待自动化);历次「59 条」为漏计。

十一、疑似提示注入

本轮扫描的提交信息、测试数据、日志、报告文本中未发现指令性内容。所有外部文本均按数据处理,未改变审查约束。