Procházet zdrojové kódy

test(tdd): 测试负责人 第62轮 全量实测 231类/1847例/1727绿=93.50% (剔环境93.94%) · 36红类/116红例 · 恒等式1838-20+3+26=1847误差0 · 与20:20轮全字段零漂移(第7次) · 定位一步可达通过: WIP修3行Mockito即-42红, 后端95.78%/合计96.37% · 新增B-29~B-32 · 门禁不通过(有条件)

cfc-tester před 6 dny
rodič
revize
cbf23a8e24

+ 359 - 0
docs/tdd/test/automation-run-2026-11-06-2310.md

@@ -0,0 +1,359 @@
+# 测试负责人工作汇报 · 2026-11-06 23:10(定时自动化 · 第 62 轮)
+
+| 项目 | 内容 |
+|------|------|
+| 汇报人 | 测试负责人(cfc-tester) |
+| 汇报周期 | 2026-11-06 20:56 ~ 2026-11-06 23:10(第 62 轮 · 全量轮) |
+| 负责模块/单元 | cfc-backend(359 控制器)/ cfc-frontend / cfc-web / tests 根级 / cfc-langgraph |
+| 执行档 | **review 档(离线)** — 不联网、不装依赖、不启停服务、不改被审源码、不推送业务代码 |
+| 权威基线 | 干净基线 `origin/cfclub` = **`98e255c10`**,独立工作树 `D:\_wt_r2135`(`--detach`,跑测后清理)。远端 `origin/cfclub` 已到 `a2e19375e`,`98e255c10..a2e19375e` 仅 cfc-web 版本号 bump + 研发巡检报告,**零源码差异** |
+| 主工作区状态 | HEAD `98e255c10`(分支 `cfclub`),**39 项 WIP 未提交**(11 后端测试 + 8 pytest + 2 前端 spec + 台账/日志/报告);本轮**零侵入**,WIP 另在隔离副本单独评估(见 1.7) |
+| 环境 | JDK 1.8.0_25 + Maven 3.6.1 `-o` 离线;后端全量 **50:41**(BUILD SUCCESS) |
+
+> **为何仍用独立工作树**:主工作区 11 个 integration 测试文件 WIP 使 `testCompile` 失败(B-26 未解除),直接在主工作区跑会得到「0 例执行」的空结果。按测试批次隔离纪律(需求 B)在干净基线执行全量,另用隔离副本验证 WIP 价值。
+
+---
+
+## 一、本轮工作数据汇总
+
+### 1.1 测试用例建设
+
+| 指标 | 数量 | 说明 |
+|------|------|------|
+| **本轮新增测试用例数*** | **0** | 测试角色不造用例;无 SRS/场景变更触发(见 SRS 闸门)。团队 WIP 中另有 2 个前端 spec(17 例)+ 20 个 pytest 用例在途,未入库不计入 |
+| **本轮验证执行测试数*** | **2299** | 后端全量 1847 + 小程序 296 + 管理端 90 + 根级 23 + pytest 43(全部本轮实跑) |
+| **用例通过率** | **93.43%** | = 2148 PASS ÷ 2299 执行 |
+
+**分模块通过率**:后端 **93.50%**(1727/1847;剔 8 例环境红后 **93.94%**);小程序 **100%**(296/296);管理端 **100%**(90/90);根级 **47.83%**(11/23);pytest **55.81%**(24/43)。
+
+**SRS 闸门**:`git log --since="2026-11-06 20:56" -- docs/superpowers docs/33 docs/10 tests/user-scenarios tests/test-cases` → 零需求/场景变更 → 本轮无需因需求变更新增用例。
+
+**恒等式校验(B-27 口径)**:`@Test 1838 − 20(3 个类级 @Disabled 内的用例)+ 3(surefire 占位)+ 26(参数化展开 27−1)= 1847`,**误差 0**;`Skipped 4 = 3 类级占位 + 1 方法级`。
+
+**静态度量**:`@RestController` 口径控制器 **359**;handler **1935 @PostMapping + 8 @GetMapping**(3 文件仍违 AGENTS.md「统一 @PostMapping」);测试文件 **232**;`@Test` **1838**;`@ParameterizedTest` 1 类;类级 `@Disabled` 3 类 + 方法级 1;pom **无 jacoco / pitest**(覆盖率、变异测试无工具,未实测)。
+
+### 1.2 会话与任务分发
+
+| 指标 | 数量 | 说明 |
+|------|------|------|
+| **分派任务数*** | **0** | 测试角色不派发(纪律) |
+| **恢复智能体会话数*** | **0** | — |
+| **当前在用会话数** | **0** | 全量执行在负责人本机 + 独立工作树完成 |
+
+### 1.2b 各会话当前工作状态列表
+
+| 会话标签 | 会话 ID | 当前状态 | 当前任务 | 静默/空闲时长 | 工作目录 | 备注 |
+|----------|---------|----------|----------|---------------|----------|------|
+| —(本轮无会话) | — | `—` | 测试执行由负责人本机完成 | — | **不干净**(39 项未提交:11 后端测试 + 8 pytest + 2 前端 spec + 台账/日志) | 研发/主理人收口(O-5);测试角色不代提交他人 WIP |
+| 远端研发巡检会话 | (见研发负责人 2117 轮报告) | `done` | 研发侧闭环巡检 | — | 干净 | 与测试无在途任务冲突 |
+
+### 1.3 问题处置
+
+| 指标 | 数量 | 说明 |
+|------|------|------|
+| **新测试发现问题数*** | **4** | ① **B-29**(P0)WIP 已能一修转绿 42 例,却被 3 行 Mockito 误用阻断全仓 `testCompile`;② **B-30**(P1)场景/用例台账与自动化资产**零编号锚点**(784 条 TC 无一条被测试资产引用);③ **B-31**(P1)`application.yml` **7 处明文凭据**;④ **B-32**(P2)场景/用例度量口径跨轮漂移(215 vs 244、784 vs 492) |
+| **已解决测试相关问题数*** | **0** | 本轮为测量与归因轮,未做测试侧改动(不改被审源码纪律) |
+| **待解决测试相关问题数** | **9** | P0:B-26(编译阻断)、B-29(WIP 未入库);P1:B-18(A 类)、B-13(环境 8)、P-2 契约 3 红、B-19(pytest)、B-30(场景锚点)、B-31(凭据);P2:B-32(口径) |
+
+### 1.4 本轮 git 提交与推送证据(真理证据)
+
+| 提交 sha | 关联任务/能力键 | 阶段 | 触及文件类型 | 目标分支 | 已推送远端 | 备注 |
+|----------|-----------------|------|--------------|----------|------------|------|
+| `eac4bff1f`(health.report.createReport 实现) | health.report.createReport | YELLOW | 实现 | origin/cfclub | **是** | `merge-base --is-ancestor` 复核通过 |
+| `c3e32460a`(dan.assessment.getActiveMaterial 实现) | dan.assessment.getActiveMaterial | YELLOW | 实现 | origin/cfclub | **是** | 同上 |
+| 本轮报告/台账提交 | 第 62 轮汇报 | — | 文档 | cfclub | 见推送回执 | 仅文档,不触碰 WIP |
+
+> 本轮无 RED/YELLOW/GREEN 阶段推进(测试角色未登记新键);状态机 5 键维持 GREEN(见 1.5)。
+
+### 1.5 状态机阶段分布(全局进度)
+
+| 阶段 | 键数 | 备注 |
+|------|------|------|
+| UNTRACKED | 0 | 目标池无未入池键 |
+| RED | 0 | 历史 3 个伪 RED 已转 GREEN(第 20 轮起) |
+| YELLOW | 0 | — |
+| GREEN | **5** | health.report.createReport / dan.assessment.getActiveMaterial / guide.trainingPlan.getPlanDetail / admin.auth.login / health.report.upload;`state.json` `updated_at` 2026-11-06 16:58 |
+| DONE | 0 | 部署验证未回写(`deploy_verify` 未配置部署会话) |
+
+### 1.6 数据源健康度
+
+| 数据源 | 读取键数 | 是否正常 | 备注 |
+|--------|----------|----------|------|
+| 需求侧(⏳ wish) | 0 | 正常 | 无未实现键,目标池为空(与状态机 5 键全 GREEN 一致) |
+| 契约常量(contract) | 15 类 / 176 例 | 正常 | 契约套件本轮在全量中实跑,见 1.8 |
+| 测试用例引用(test_case_map) | 784 | 正常 | 12 个 TC 文档解析成功 |
+| 执行结果回填(case_results) | 231 类 / 1847 例 | 正常 | surefire XML 全量回收,`silent_missing = 0` |
+
+### 1.7 WIP 评估(本轮核心:**一修即绿 42 例,卡在 3 行编译错误**)
+
+> 主工作区 39 项 WIP 为团队在途的「测试校准批次」。为量化其价值,在隔离副本(干净基线 + 带入全部 WIP 文件)中仅做 **3 行 Mockito API 修正**后定向复跑,**未触碰主工作区**。
+
+| 项目 | 基线(已入库) | WIP + 3 行修正 | Δ |
+|------|----------------|----------------|---|
+| 后端 11 个被改测试类 | 170 例 / **48 红** | 170 例 / **6 红** | **−42 红** |
+| 其中逐类 | Article 9、GuideOrder 8、ProductOrder 6、GuideFamilyTask 5、GuideRolePermission 5、Auth 4、Payment 4、Product 3、GuideTeam 2、Family 1、Stats 1 | GuideFamilyTask 3、GuideRolePermission 2、Stats 1;**其余 8 类全绿** | 8 类清零 |
+| pytest | 43 例 / 24 绿 19 红(55.81%) | 63 例 / 49 绿 / 2 红 / 12 skip(执行口径 **96.1%**) | **+25 绿** |
+| 小程序前端 | 296 例(14 套件) | 313 例(16 套件)全绿 | +17 例全绿 |
+| **合计预测** | 2148 / 2299 = 93.43% | **2215 / 2299 = 96.37%** | **+67 绿,越 G1 95% 阈值** |
+
+**阻断点(唯一)**:`ArticleControllerTest.java:201/215/226` 三处 `when(articleService).recordRead(...)` → 应为 `when(articleService.recordRead(...))`。修正这 3 行,WIP 即可编译、可入库、可把后端通过率推到 **95.78%**((1727+42)/1847)。
+
+**WIP 剩余 6 红**(修正编译后仍红,需研发/数据侧):`GuideFamilyTaskControllerTest.getFamilyTaskOverview_WithChildren / reviewTask_Success / batchReviewTasks_Success`、`GuideRolePermissionTest.reviewTask_TeacherAllowed / batchReview_TeacherAllowed`(审核链 NPE 与计数为 0,与 CF 预估挂载 B-22 同区)、`StatsControllerTest.familyCompletion_NoFamily`(文案已改为「请先创建或加入家庭」)。
+
+### 1.8 契约与关键特性键(全量实跑,非定向)
+
+| 契约类 | 结果 | 备注 |
+|--------|------|------|
+| `TaskControllerReviewTest`(SC-P-11) | **17/17 绿** | B-21 收口后第 5 轮稳定 |
+| `DimensionRegistryTreeTest` | 9/9 绿 | — |
+| `JwtInterceptorLoginRequiredPathTest` | **28/28 绿** | 鉴权清单全条目参数化守护(B-22 收口) |
+| `RewardEstimateControllerEstimateTest` + `RewardRuleServiceEstimateTest`(SC-X-22) | **11+21=32/32 绿** | 已入库(B-23 闭环) |
+| `CfBalanceServiceTest` | 25/25 绿 | B-10 第 12 轮无复发 |
+| `HealthDimensionControllerTest` | 15/15 绿 | B-18 已修 |
+| `DimensionRegistryMapContractTest` | **4/7(3 红)** | P-2 口径未拍板,唯一契约红源 |
+
+---
+
+## 二、向研发提出的改进建议(五要素问题清单)
+
+### P-1【P0】3 行 Mockito 误用阻断整个模块测试(B-26/B-29)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 主工作区 `mvn test-compile` 失败,全仓 232 个测试源无法编译 → 任何人在主工作区跑 `mvn test` 都会得到「0 例执行」,而 11 个 WIP 测试文件已能把 48 红降到 6 红 |
+| ② 测试 bug 点 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleControllerTest.java:201 / :215 / :226`;错误 `recordRead(long,Object,Object,int) 位置: 接口 OngoingStubbing<ArticleService>` |
+| ③ 最优修改方案 | 将 3 处 `when(articleService).recordRead(eq(1L), isNull(), isNull(), eq(30)).thenReturn(new HashMap<>())` 改为 `when(articleService.recordRead(eq(1L), isNull(), isNull(), eq(30))).thenReturn(new HashMap<>())`(方法调用移入 `when(...)` 内;`ArticleService.recordRead` 返回 `Map<String,Object>`,见 `ArticleService.java:409`) |
+| ④ 修改目的 | 恢复 `testCompile` 可用性,使团队已完成的 42 例转绿成果能入库生效;后端通过率 93.50% → **95.78%**(越 G1 阈值) |
+| ⑤ 闭环判定 | 主工作区 `mvn -o -B test-compile -DskipTests=false` **0 错**(232 源)→ `mvn -o -B test` 全量 1847 例、红例 ≤ 74、F/E 无编译类错误;报告复核 G1 ≥95% |
+
+### P-2【P0】测试资产未入库(B-29/G12)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 39 项 WIP 含 11 个后端测试、8 个 pytest 文件、2 个前端 spec(`__tests__/specs/coupon-claimed-actions.test.js`、`team-invite-share.test.js`),全部只在主工作区磁盘上;`git clean -fd` 或分支切换即静默丢失(同类事故已发生 3 次:B-15/B-23/B-28) |
+| ② 测试 bug 点 | `git status --porcelain` 39 项;`git ls-files cfc-frontend/__tests__/specs` 零命中;`1a2b.spec.js` 已被删并留 `.dead` 后缀未收口 |
+| ③ 最优修改方案 | 先修 P-1 的 3 行 → `mvn test-compile` 通过后 `git add`(11+8+2+台账)→ 提交信息注明「测试校准批次:48 红→6 红」→ push `origin/cfclub` → `--clean-check` 复核为 0 项 |
+| ④ 修改目的 | 让 42 例外后端 + 25 例 pytest + 17 例前端转绿成果进入版本基线,避免「测了但没留下」;同时闭环 G11/G12 |
+| ⑤ 闭环判定 | `git status --porcelain` 为空;`git ls-files` 命中上述 21 个文件;连续 2 轮全量复跑结果与入库版本一致 |
+
+### P-3【P1】WIP 之后仍红的 74 例(A 类残余,逐类收敛)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 116 红例中,WIP 已覆盖 42 例;剩余 74 例仍为测试装置缺陷或需研发确认。最大块:`CfCommissionServiceSettleTest` 8(`WantedButNotInvoked: earnByRule`)、`ProductOrderServiceFulfillmentMultiModeTest` 6(matcher 混用 + `stubBuyerWithOpenid` NPE)、`DanReportParseServiceTest` 4、`ArticleWorkflowTest` 3(文案已含「或已撤回」)、`ProductOrderServiceUpdateExpressFieldTest` 3(`ArgumentsAreDifferent`)、`WishControllerTest` 2(`childId`→`memberId`)、`GuideTeamControllerTest` 2 |
+| ② 测试 bug 点 | `CfCommissionServiceSettleTest`(`earnByRule` 未 stub `calcOrderPpoints` 依赖 → `distributeToReferrers` 在 `CfCommissionService.java:196` 因 `basePpoints<=0` 提前 return);`ProductOrderServiceFulfillmentMultiModeTest.setUp:37`(`InvalidUseOfMatchers`);`ArticleWorkflowTest:205/217/228`;`ProductOrderServiceUpdateExpressFieldTest`(`uploadShippingInfo` 期望参数漂移) |
+| ③ 最优修改方案 | ① `CfCommissionServiceSettleTest` 补 `calcOrderPpoints` 依赖桩(或改断 `ppointConsumptionLogMapper` 前置状态);② `ProductOrderServiceFulfillmentMultiModeTest` 统一 `any()/eq()` 配对并修 `stubBuyerWithOpenid:71` 的 `User` 桩;③ 文案类断言改「包含关键字」而非全等;④ `uploadShippingInfo` 期望参数按现实现(含 `logisticsType`)更新 |
+| ④ 修改目的 | 把 G1 从 95.78% 推向 99%+,G2 非环境红从 66 降到个位数,使「全绿」可预期 |
+| ⑤ 闭环判定 | 上述 7 类定向复跑全绿 + 下一轮全量 F/E 逐类差集为空 |
+
+### P-4【P1】planner 培训认证闸门致 11 例恒红(环境/数据)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 11 例断言期望 200/业务文案,实得 **403 规划师未完成【planner】培训认证**:`GuideOrderControllerTest` 5、`GuideRolePermissionTest` 3、`PlannerBindInviteFlowTest` 3 |
+| ② 测试 bug 点 | `GuideOrderControllerTest.java:142`(getOrderDetail_Success)、`:108`(NullParams);`GuideRolePermissionTest.java:314/335` |
+| ③ 最优修改方案 | 测试夹具里给 planner 账号种 `teacher_status/培训认证通过` 数据(或 `@Sql` seed + `@Transactional` 回滚),或在测试 profile 关闭该闸门开关 |
+| ④ 修改目的 | 消除 11 例与代码无关的恒红,避免掩盖真实回归(当前每轮固定占用红例名额) |
+| ⑤ 闭环判定 | 3 类定向复跑 11/11 绿,且全量红例数下降 ≥11 |
+
+### P-5【P1】3 类 `@SpringBootTest` 硬编码本机 MySQL(B-13,8 例恒红)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | `AdminFamilyOverviewControllerTest`、`FamilyAdminOverviewServiceTest`、`UserServiceFamilyNameLinkTest` 的 `spring.datasource.url` 写死 `127.0.0.1:3306` → `Failed to load ApplicationContext`,每轮固定 8 例 E |
+| ② 测试 bug 点 | `AdminFamilyOverviewControllerTest.java:21-22` 等 3 处 |
+| ③ 最优修改方案 | 改 `@ActiveProfiles("test")` + `src/test/resources/application-test.yml` 指向 `192.168.16.251` 测试库(Hikari 池上限 4) |
+| ④ 修改目的 | 8 例从「环境红」转「真实验证」,剔环境后通过率口径才有意义 |
+| ⑤ 闭环判定 | 3 类 8/8 绿;`grep -rl '127.0.0.1:3306' src/test` 零命中;全量 `Exception during pool initialization` 归零 |
+
+### P-6【P1】契约 3 红未拍板(P-2 `MapContract`)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | `DimensionRegistryMapContractTest` 4/7:`map_emptyLegacy_returnsNullData`(期望 data=null 实得 "")、`map_unknownLegacy_returnsNullData`(实得原串)、`map_missingLegacy_returnsBadRequest`(期望 400 实得 200) |
+| ② 测试 bug 点 | `DimensionRegistryMapContractTest` 3 个用例 |
+| ③ 最优修改方案 | 需求侧拍板口径后二选一:A) 实现改为空/未知 legacy 返回 `data=null`、缺失返 400;B) 契约改为返回原串/200 并删掉 3 条断言 |
+| ④ 修改目的 | G8 契约红归零,契约套件可并入 CI 作为回归网 |
+| ⑤ 闭环判定 | 该类 7/7 绿且纳入 CI backend job |
+
+### P-7【P1】pytest 2 红 + `tests/qna` 死资产
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | WIP 后 `test_graph.py::test_graph_valid_output` / `test_graph_invalid_llm_response_rejected` 仍 `AttributeError`;`tests/qna/test_graph.py` 引用不存在的 `src.qna`,收集期即报错(WIP 用 `collect_ignore` 绕过而非修复) |
+| ② 测试 bug 点 | `cfc-langgraph/tests/test_graph.py`;`cfc-langgraph/tests/qna/test_graph.py` |
+| ③ 最优修改方案 | `test_graph` 2 例按新 `StubLLM` 返回值调整断言;`tests/qna/test_graph.py` 删除或重写指向现存模块 |
+| ④ 修改目的 | pytest 执行口径 96.1% → 100%,`collect_ignore` 的临时绕过可撤 |
+| ⑤ 闭环判定 | `pytest tests -q` 0 failed 0 error(skip 仅 llm_live) |
+
+### P-8【P1】根级 12 红(B-16 凭据夹具 + 死资产)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | `tests/` 根级 23 例 11 绿 12 红:`plan-chain.spec.js` 2 例因 `ADMIN_PHONE/ADMIN_PASSWORD` 为空导致登录 500;`mini-games-api.spec.js` 10 例 401(无 token) |
+| ② 测试 bug 点 | `tests/integration/plan-chain.spec.js:21-22`、`tests/integration/mini-games-api.spec.js` |
+| ③ 最优修改方案 | 新增 `tests/.env.test` + `globalSetup` 自动登录取 token,CI 注入 `API_BASE_URL`;`1a2b.spec.js` 的 `.dead` 收口为删除 |
+| ④ 修改目的 | 根级套件从 47.83% → 100%,不再每轮固定 12 红噪声 |
+| ⑤ 闭环判定 | 根级 23/23 绿;`.dead` 文件清理完毕 |
+
+### P-9【P1】场景/用例台账与自动化资产零编号锚点(G10 不可量化)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 215 个用户场景、784 条 TC,但**没有任何一条 TC 编号出现在 348 个测试资产中**(0/784);场景被 Playwright spec 字面引用仅 6 个(2.8%),仅 155 个场景(72.1%)在用例台账里被映射 |
+| ② 测试 bug 点 | 测试资产侧无 TC 编号注释/注解;`tests/test-cases/*.md` 的 `对应 e2e` 列与实际文件名脱节(如 `e2e/roles/parent/../tasks`) |
+| ③ 最优修改方案 | 约定「每个自动化用例方法/描述首行注明 `@TC-P-01`」,先用脚本对 12 个 TC 文档做反向核对生成缺口清单,再按角色分 4 批补注释;`对应 e2e` 列用真实路径校验 |
+| ④ 修改目的 | 让「场景→用例→自动化」可双向追溯,SRS 覆盖率才可量化闭环(当前无法回答「哪些场景没测」) |
+| ⑤ 闭环判定 | 编号锚点覆盖 TC ≥90%;生成「场景→TC→资产」三列对照表且缺口清单为 0 |
+
+### P-10【P1】`application.yml` 7 处明文凭据(安全)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | `cfc-backend/src/main/resources/application.yml` 存在 **7 处** `password/secret/api-key/appsecret` 明文赋值(本报告不复制取值) |
+| ② 测试 bug 点 | `application.yml`(`spring.datasource.*`、微信 `appsecret`、第三方 key 等行) |
+| ③ 最优修改方案 | 改为环境变量占位 `${DB_PASSWORD}` / `${WX_APPSECRET}`,本地用 `.env`(`.gitignore`),生产用配置中心/K8s Secret;同步轮换已泄露凭据 |
+| ④ 修改目的 | 消除源码级凭据泄露(当前任何有仓库读权限者可直接取用生产/测试库口令) |
+| ⑤ 闭环判定 | `grep -rniE '^\s*(password|secret|api[-_]?key|appsecret)\s*:\s*\S+' resources/` 零命中;服务在注入环境变量后启动正常 |
+
+### P-11【P2】8 处 `@GetMapping` 违反项目接口规约
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | `AdminSystemPromptController`、`DimensionRegistryController`、`CfBalanceController` 共 8 处 `@GetMapping`,违 AGENTS.md「统一 `@PostMapping`,禁止 Get/Put/Delete」 |
+| ② 测试 bug 点 | 上述 3 文件的 mapping 注解 |
+| ③ 最优修改方案 | 改为 `@PostMapping` 并同步前端调用与 `API_REFERENCE.md`;不可改的标 `410 Gone` 并注释 |
+| ④ 修改目的 | 接口风格一致,避免小程序端/管理端两套调用约定 |
+| ⑤ 闭环判定 | `grep -rn '@GetMapping' controller/` 零命中,前端全绿 |
+
+---
+
+## 三、本轮阻塞与风险
+
+| 阻塞项 | 影响范围 | 阻塞类型 | 处置进展 | 需要协调 |
+|--------|----------|----------|----------|----------|
+| B-26/B-29:3 行 Mockito 误用致全仓 `testCompile` 失败 | 后端 232 测试源 / 1847 例;42 例可转绿成果无法入库 | 研发(测试装置) | 已定位到行,给出逐行改法 | 研发或主理人执行 3 行修正(测试角色不改被审源码) |
+| 39 项 WIP 未入库 | 42 后端 + 25 pytest + 17 前端绿例随时可丢 | 研发/流程 | 已量化价值(+67 绿,96.37%) | 主理人裁决入库窗口(O-5) |
+| planner 培训认证闸门 11 例 | 3 类恒红,掩盖真实回归 | 需求/数据 | 已给夹具方案 | 需求侧确认测试账号资质数据 |
+| 契约 3 红(MapContract) | G8 无法归零,契约套件不能进 CI | 需求/设计 | 两次口径待拍板 | 主理人裁决 P-2 口径 |
+| 场景覆盖率不可量化(G10) | 无法回答「SRS 是否全覆盖」 | 测试/流程 | 已量化 2.8%/72.1% 并给锚点方案 | 需 4 批补注释的工时投入 |
+
+---
+
+## 四、下轮工作计划
+
+| 计划项 | 预计完成时间 | 前置依赖 | 备注 |
+|--------|--------------|----------|------|
+| 复验 P-1 的 3 行修正后全量结果(预期 95.78%) | 下轮触发(约 1h 内) | 研发/P-1 落地 | 全量 clean 复跑,逐类差集对账 |
+| WIP 入库后连续 2 轮零漂移确认 | 入库后第 2 轮 | P-2 完成 | 若 2 轮一致,G11/G12 可关闭 |
+| planner 闸门 + 环境 8 例修复后复验(预期 G2 ≤ 55) | 下轮 | P-4/P-5 | 需测试数据 seed |
+| 场景→TC→资产三列对照表首版 | 下轮 | P-9 第 1 批 | 脚本生成,交需求侧核对 |
+| 契约 MapContract 口径确认后复验 | 待裁决 | 主理人裁决 | 裁决后当轮即可闭环 G8 |
+
+---
+
+## 附录
+
+### 附录 A:本轮新增测试用例明细
+
+**无**(测试角色不造用例;无 SRS/场景变更触发)。在途未入库用例见 1.7 WIP 评估(前端 2 spec / 17 例,pytest 20 例)。
+
+### 附录 B:任务分派与会话恢复明细
+
+**无派发、无恢复**(测试角色不派发 opencode 会话)。
+
+### 附录 C:新发现问题明细
+
+| 问题 ID | 能力键/任务号 | 问题类型 | 路由去向 | 登记时间 | 处置状态 | 关联 sha |
+|---------|---------------|----------|----------|----------|----------|----------|
+| B-29 | cfc-backend testCompile | 阻塞(P0) | 研发/测试 | 2026-11-06 23:10 | 待处理 | 主工作区 WIP(未入库) |
+| B-30 | 场景/TC 台账 | 度量缺口(P1) | 测试/需求 | 2026-11-06 23:10 | 待处理 | — |
+| B-31 | `application.yml` | 安全(P1) | 研发 | 2026-11-06 23:10 | 待处理 | — |
+| B-32 | 度量口径 | 流程(P2) | 测试 | 2026-11-06 23:10 | 待处理 | — |
+
+---
+
+## 五、20 类测试覆盖矩阵(三态)
+
+> 三态口径:「已发现」= 本轮实测有证据;「未发现」= 扫描未命中(≠ 项目没做);「待核实」= 有线索但证据不足。
+
+| # | 测试类型 | 状态 | 证据(本轮实测) |
+|---|----------|------|------------------|
+| 1 | 单元测试 | 已发现 | 后端 231 类 1847 例;小程序 296;管理端 90;pytest 43 |
+| 2 | 测试覆盖率 | 未发现 | pom 无 jacoco/pitest,无覆盖率工具(未实测,不得记通过) |
+| 3 | 变异测试 | 未发现 | 无 pitest,未实测 |
+| 4 | 集成测试 | 已发现 | `integration/` 41 类;`@SpringBootTest` 3 类;GuideModuleIntegrationTest 真库 |
+| 5 | 契约测试 | 已发现 | 15 类 176 例,173 绿 / 3 红(MapContract) |
+| 6 | 接口 API 测试 | 已发现 | MockMvc/直接调用;Playwright API 级 83 例(上轮 execute 档 91.67%,本轮未联网未跑) |
+| 7 | 端到端 E2E | 待核实 | 76 个 spec 存在;UI 级因环境不具备长期未实测;根级 23 例仅 11 绿 |
+| 8 | 验收 UAT | 未发现 | 无 UAT 记录/脚本 |
+| 9 | BDD 规格 | 未发现 | 无 feature 文件 |
+| 10 | 冒烟测试 | 待核实 | `_smoke_browser.spec.js` 存在;本轮未跑(未授权联网) |
+| 11 | 回归测试 | 已发现 | 本轮全量 2299 例,与 20:20 轮全字段零漂移(第 7 次) |
+| 12 | 探索性测试 | 未发现 | 无 chartered session 记录 |
+| 13 | 性能测试 | 未发现 | 无压测脚本/工具;仅采集 Maven 时长(50:41,B-24 时延延续) |
+| 14 | 可靠性测试 | 待核实 | `HealthReportController` 重试/幂等契约 5 例绿;无故障注入 |
+| 15 | 安全测试 | 待核实 | 静态扫描发现 7 处明文凭据(B-31)、8 处 `@GetMapping`;SAST/DAST/依赖漏洞本轮未跑(未联网/无工具) |
+| 16 | 兼容性测试 | 待核实 | 小程序 296 例基于 mock,未覆盖真机/多端;Playwright 仅 chromium 配置 |
+| 17 | 可用性测试 | 未发现 | 无可用性/体验评测记录 |
+| 18 | 无障碍测试 | 未发现 | 无 axe/WCAG 检查 |
+| 19 | QA 流程 | 已发现 | 阻塞台账 B-1~B-32、三方文档通道、CI 最小管线(.gitlab-ci.yml) |
+| 20 | 质量度量 | 已发现 | 恒等式误差 0、零漂移对账、三口径覆盖(18.1%/12.0%)、场景绑定率 2.8%/72.1% |
+
+### 覆盖缺口清单(G-1~G-8)
+
+| 缺口 | 类型 | 现状 | 风险 | 建议测试设计 | 优先级 | 闭环方式 |
+|------|------|------|------|--------------|--------|----------|
+| G-1 | 场景→自动化 | TC 编号 0/784 出现在资产;spec 字面引用 6/215 | 无法证明 SRS 覆盖 | 资产内 `@TC-*` 锚点 + 反向核对脚本 | P1 | P-9 |
+| G-2 | 覆盖率 | 无 jacoco/pitest | 盲区不可见 | 引入 jacoco(离线插件包)出报告 | P1 | 插件化后每轮出 jacoco.xml |
+| G-3 | E2E | 76 spec 长期未实跑 | 用例腐化 | 本地 9082 + `playwright.config.api.js`(不 reset 共享库) | P1 | 纳入每轮 |
+| G-4 | 回归网 | 无 CI 自动跑测试(CI 仅 test-compile,3 job 均 manual) | 「绿」是瞬时绿(B-21 已证) | CI 加 backend-test(失败容忍白名单)+ pytest + jest | P1 | G6 门禁 |
+| G-5 | 性能 | 仅总耗时,无基线 | 劣化不可判 | 固化「总耗时/Top5 单类」±5% 带 | P2 | 报告附录固化 |
+| G-6 | 安全 | 无 SAST/依赖扫描(本轮未联网) | 凭据与漏洞不可见 | 离线 OWASP 依赖检查 + 明文凭据扫描进 CI | P1 | B-31 修复后加扫描 |
+| G-7 | 兼容/无障碍 | 仅 mock 单端 | 真机问题漏检 | 真机冒烟 + axe 检查 | P2 | 独立环境 |
+| G-8 | 异常流覆盖 | TC 异常流 474/784(60.5%)设计充足,但自动化绑定近 0 | 异常路径实际未验证 | 优先给 `-N` 负向 TC 补自动化 | P1 | 与 G-1 同步 |
+
+---
+
+## 六、门禁结论
+
+| 门禁 | 阈值 | 实测 | 结论 |
+|------|------|------|------|
+| G1 后端用例通过率 | ≥95% | **93.50%**(WIP 修正后 95.78%) | ❌(一步可达 ✅) |
+| G2 非环境红例 | 0 | **108**(WIP 修正后 66) | ❌ |
+| G3 前端用例 | 386/386 | **386/386**(296+90) | ✅ |
+| G4 测试类编译 | 0 错 | **232/232**(干净基线) | ✅(主工作区 WIP 为 ❌,见 G11) |
+| G5 完整性 | 231/231、沉默 0 | **231/231、沉默 0、dump 0** | ✅ |
+| G6 CI 自动回归 | 测试进 CI 自动跑 | `.gitlab-ci.yml` 已入库,但后端仅 `test-compile`、3 job 均 `when: manual` | ❌(有条件) |
+| G7 状态机 | 5 键 GREEN 且非伪绿 | **5 键 GREEN**(16:58),契约 17/17、28/28、32/32 支撑 | ✅(第 5 轮) |
+| G8 契约红 | 0 | **3**(MapContract) | ❌ |
+| G9 pytest 通过率 | ≥95% | **55.81%**(WIP 执行口径 96.1%) | ❌(一步可达 ✅) |
+| G10 场景自动化绑定 | ≥80% | **2.8%**(spec 字面)/ **72.1%**(用例台账映射) | ❌ |
+| G11 WIP 入库 | 0 项未提交 | **39 项** | ❌ |
+| G12 测试资产入库 | 全部入库 | 2 前端 spec + 11 后端 + 8 pytest 未入库 | ❌ |
+
+# **结论:不通过(有条件)**
+
+**判定依据(量化)**:
+1. 目标「所有测试用例都测试通过」**未达成**:2299 例中 151 例未通过(93.43%),其中后端 120 例(F70/E46/S4)、根级 12 例、pytest 19 例。
+2. 目标「覆盖所有 SRS 及用户场景(含异常流)」**未达成**:场景 215 个中仅 6 个(2.8%)在自动化 spec 中有编号级引用;TC 784 条(异常流 474 条 / 60.5%)无一条与测试资产建立编号锚点 → 覆盖不可量化闭环。
+3. **但本轮定位到「一步可达通过」路径**:修 3 行 Mockito 误用 + 合并 39 项 WIP → 后端 95.78%、pytest 96.1%、合计 **96.37%**,G1/G9 转绿、G11/G12 同步闭环;剩余红例收敛到 5 类(planner 闸门 11 + 环境 8 + 契约 3 + 审核链 5 + 散例)。
+
+**复评条件**:① P-1 落地后全量 clean 复跑 G1 ≥95%;② WIP 入库且连续 2 轮零漂移;③ G1/G9/G11/G12 同时为 ✅ 时提请复评;④ 场景锚点(P-9)≥90% 才可声明「SRS 覆盖闭环」。
+
+---
+
+## 附:本轮证据文件
+
+| 文件 | 内容 |
+|------|------|
+| `/d/_r2135_backend.log` | 后端全量 `mvn -o -B clean test`(50:41,BUILD SUCCESS) |
+| `/d/_r2135_agg.json` | 231 类聚合(tests/pass/F/E/S/红类/环境红/沉默类) |
+| `/d/_r2135_attr.json` / `_r2135_frames.json` | 116 红例逐例消息与堆栈帧 |
+| `/d/_r2135_frontend.log` / `_r2135_cfcweb.log` / `_r2135_root_tests.log` | 前端 296 / 管理端 90 / 根级 23 |
+| `/d/_r2135_pytest.log` / `_r2135_wip_pytest.log` | pytest 基线 43 例 / WIP 63 例 |
+| `/d/_r2135_wip_compile.log` / `_r2135_wip_tests.log` | WIP 编译失败证据 + 修正后定向 170 例 |
+| `/d/_r2135_scene.json` | 场景 215 / TC 784 / 绑定率 |
+| `/d/_r2135_aggregate.py` / `_r2135_attr.py` / `_r2135_scene.py` | 本轮度量脚本(建议纳入 `docs/tdd/tools/`,见 B-15/B-32) |
+
+> 本轮对主工作区与被审代码 **零修改**:所有执行在 `D:\_wt_r2135` 独立工作树及其隔离副本内完成;主工作区 39 项 WIP 原样保留。

+ 4 - 0
docs/tdd/test/blockers.md

@@ -33,3 +33,7 @@
 | B-26 | cfc-backend 主工作区 testCompile 阻断(11 个 integration 测试文件 WIP) | 研发 | 主工作区 `mvn testCompile` 失败:`ArticleControllerTest.java:201/215/226` 三处编译错误(`recordRead` 找不到符号,位置 `OngoingStubbing<ArticleService>`)。**根因(20:20 轮细化)**:WIP 采用 `when(articleService).recordRead(eq(1L), isNull(), isNull(), eq(30)).thenReturn(new HashMap<>())`——`when(T mock)` 返回 `OngoingStubbing<T>`,其无 `recordRead` 方法,属 Mockito API 误用;主代码 `ArticleService.recordRead(Long,Long,Long,int)` 返回 `Map<String,Object>`(`ArticleService.java:409`),故正确写法为 **`when(articleService.recordRead(...)).thenReturn(...)`**(方法调用置于 `when(...)` 内)。**同时**已提交基线本身亦为 A 类装置缺陷:3 例用 `doNothing().when(...).recordRead(...)` 对非 void 方法 stubbing → `Only void methods can doNothing()`。测试侧已用独立 worktree 干净基线(`origin/cfclub` `e4ce9f80a`)旁路完成全量 231 类 1847 例 93.50%,证明**非主线回归**。**登记留痕丢失**:本条 19:10 首登后未入库,19:37 工作区文件被回滚覆盖(与 B-15/B-23 同类资产丢失),20:20 轮据实测重建。建议:① 按上述正确写法修 3 处并同批复核 `getPublicList`/`getFeatured` 8 处实参个数;② testCompile 复验 0 错后提交推送 | 测试(59/60 轮实测登记) | 2026-11-06 19:10(20:20 细化重建) | 待处理 |
 | B-27 | `@Test` 恒等式失效(引入 @ParameterizedTest 后口径未修订) | 测试 | 20:20 轮全量实测 `@Test 1838 − 20(3 类类级 @Disabled)+ 3(surefire 占位)= 1821`,但 surefire 实际执行 **1847** 例,差 **26**。根因:`cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredPathTest.java:62` 引入 `@ParameterizedTest + @MethodSource`,该类单注解展开 **27** 例(surefire `tests=28` = 1 @Test + 27 展开)。修订后恒等式:`@Test − 类级@Disabled + 占位 + Σ(参数化展开数−1) = 执行数`(本轮 1838−20+3+26=1847,误差 0)。风险:口径不修正会把新增用例漏记/错记(B-15/B-26 同源度量漂移)。建议把计数脚本 `count_identity.py` 纳入 `docs/tdd/tools/` 并入库 | 测试(20:20 轮登记) | 2026-11-06 20:20 | 待处理 |
 | B-28 | 测试交付物跨分支丢失(第 59 轮报告 + B-26/O-5 在 cfclub 不可见) | 研发/流程 | 19:41 仓库分支由 `feature/report-upload-product-cards` 切至 `cfclub`(HEAD `df7f60af5`,merge `da2727f53`+`e205656ee`);`git merge-base --is-ancestor 963bedae7 HEAD` = **NO** → 19:12 提交的第 59 轮报告(`docs/tdd/test/automation-run-2026-11-06-1910.md`)与 B-26/O-5 台账条目**在 `cfclub` 分支不存在**(文件在磁盘上被 checkout 覆盖清除)。内容未真丢(仍在 `origin/feature/report-upload-product-cards` 祖先链上,`merge-base --is-ancestor 963bedae7 origin/feature/...` = YES),但主线不可见 → 台账审计断链。与 B-14(窗口内并发提交)/ B-15(脚本丢失)/ B-23(测试文件未入库)同族:**测试交付物没有随主线合并机制**。建议:① 主理人裁决 `git cherry-pick 963bedae7` 或合并 feature 分支;② 测试报告/台账提交统一落在 `cfclub`(主线)分支,避免分支切换即丢失;③ 跑测前记录 `git rev-parse --abbrev-ref HEAD` 与 HEAD sha,报告中固化 | 测试(20:20 轮实测登记) | 2026-11-06 20:20 | 待处理 |
+| B-29 | WIP 测试校准批次被 3 行 Mockito 误用阻断(P0) | 研发/测试 | 主工作区 39 项 WIP(11 后端测试 + 8 pytest + 2 前端 spec)**已具备大幅转绿能力**:隔离副本带入 WIP 并仅修 3 行后,11 个被改后端类 **170 例 48 红 → 6 红(−42)**,其中 Article/GuideOrder/ProductOrder/Product/GuideTeam/Payment/Family/Auth 8 类清零;pytest **24 绿 → 49 绿(执行口径 96.1%)**;前端 **296 → 313 全绿**。合计预测 **(2148+67)/2299 = 96.37%**,后端 **95.78%**(越 G1)。**唯一阻断**:`ArticleControllerTest.java:201/215/226` 三处 `when(articleService).recordRead(...)` 应为 `when(articleService.recordRead(...))`(`when(mock)` 返回 `OngoingStubbing`,无 `recordRead`;`ArticleService.recordRead` 返回 `Map`,见 `:409`)→ 修此 3 行即可编译入库。剩余 6 红:GuideFamilyTask 3(overview/reviewTask/batchReview)+ GuideRolePermission 2(reviewTask/batchReview NPE、计数 0)+ Stats 1(文案「请先创建或加入家庭」)。建议:修 3 行 → `mvn test-compile` 0 错 → `git add` 21 个测试文件 + 台账 → push → `--clean-check` 复核 | 测试(62 轮实测登记) | 2026-11-06 23:10 | 待处理 |
+| B-30 | 场景/用例台账与自动化资产零编号锚点(覆盖不可量化) | 测试/需求 | 实测 215 个用户场景(11 文件)、784 条 TC(异常流 474 = 60.5%),但 **TC 编号在 348 个测试资产中出现 0 次**(0/784);场景被 Playwright spec 字面引用仅 **6 个(2.8%)**,被用例台账映射 155 个(72.1%)。后果:无法回答「哪些 SRS 场景没有自动化」,历史各轮只能以「用例数/通过率」代替「需求覆盖率」。根因:`tests/test-cases/*.md` 的 `对应 e2e` 列与真实文件名脱节(如 `e2e/roles/parent/../tasks` 非合法路径),资产侧亦无 `@TC-*` 锚点约定。建议:① 约定每个自动化用例首行注明 TC 编号;② 写反向核对脚本生成「场景→TC→资产」三列缺口清单;③ 按角色分 4 批补锚点,优先 `-N` 负向 TC(异常流) | 测试(62 轮登记) | 2026-11-06 23:10 | 待处理 |
+| B-31 | `application.yml` 7 处明文凭据(安全) | 研发 | `cfc-backend/src/main/resources/application.yml` 存在 **7 处** `password/secret/api-key/appsecret` 明文赋值(本台账不复制取值),覆盖数据源口令、微信 appsecret 与第三方 key。任何具备仓库读权限者可直取测试/生产凭据;且历史提交已留在 git 历史中。建议:改 `${ENV}` 占位 + 本地 `.env`(gitignore)+ 配置中心/Secret 管理;**同时轮换已泄露凭据**;CI 加明文凭据扫描(gitleaks 规则集) | 测试(62 轮静态扫描登记) | 2026-11-06 23:10 | 待处理 |
+| B-32 | 场景/用例度量口径跨轮漂移(度量不可比) | 测试 | 本轮实测:场景 **215**、TC **784**(异常流 474);上一轮报告记「场景 244、TC 492(异常流 237)」。差异非增长(90 分钟内不可能新增 292 条 TC),而是**解析口径不同**(是否计入 `### 场景`(08/09 butler 17 条)、是否计入 `TC-*-N*` 负向编号、类型列是否含「权限」判异常)。与 B-15/B-27 同族:**度量脚本未入库、口径未固化** → 跨轮数字不可相减。建议:把 `_r2135_scene.py` 等脚本收进 `docs/tdd/tools/` 并入库,报告固定写「口径定义 + 脚本版本」,禁止手算 | 测试(62 轮登记) | 2026-11-06 23:10 | 待处理 |