# 测试计划 — 绩效场景全低代码能力闭环补齐 > status: propose > created: 2026-08-03 ## 0. 测试原则 - 每轮先读取 `AGENTS.md`、memory、本变更四份文档和 `code-copilot/rules/automated-testing-standard.md`,只验证本轮差异。 - 权限、状态、幂等、补偿和批量数据创建采用 Red/Green TDD;服务端是权限、公式和校验的最终可信边界。 - 普通低代码 CRUD、历史 BPMN、现有到期提醒、现有消息接收人和现有动作步骤属于强制回归范围。 - 所有测试使用合成员工、组织、评分和消息数据;日志、截图和 fixture 不包含客户真实人员信息。 - Proposal 阶段只执行文档静态检查;构建、数据库、服务和 E2E 必须在 HARD-GATE 后按 Phase 增量执行。 ## 1. 测试框架与待核基线 | 项目 | 计划 | |------|------| | 后端 | Java 17、JUnit 5、Mockito;Mapper/Flyway 使用 MySQL 8 临时库 | | 前端 | Vitest + Node 20.19.0 + Vite production build | | 流程 | Flowable 用户任务、BPMN parser/writer round-trip、任务并发与回调测试 | | 消息 | 现有站内消息服务,验证接收人解析和消息记录,不接外部协同渠道 | | E2E | 版本化脱敏低代码 fixture + 明确的加载器或人工重建步骤 + 合成数据,覆盖绩效核心流程 | | 当前基线 | 进入 `/apply` 前按最新工作区统计相关测试类、迁移版本和构建状态 | ## 2. Phase 1:节点主子表权限与草稿 ### P0 | 场景 | 预期 | |------|------| | 新 BPMN 子表权限 round-trip | `relationCode/fieldCode/readable/writable/requiredOnComplete/allowAdd/allowDelete` 无损回显 | | 历史 BPMN | 主表权限保持现状,未声明子表权限时只读 | | 自评/上级节点 | 只允许写各自评分字段,快照和公式字段只读 | | 草稿保存 | 允许空评分,仅执行类型、范围、字段权限和子记录归属校验 | | 越权主子记录 | 跨主记录行、未知关系、未知字段、新增/删除越权均被服务端拒绝 | | 历史/已办查看 | 主子表全部只读 | ### P1 - 桌面和窄屏下子表列、必填标识和行操作不重叠。 - 公式字段恶意提交被忽略并产生不含敏感值的安全审计。 ## 3. Phase 2:集合规则、公式、唯一办理命令与补偿 ### P0 | 场景 | 预期 | |------|------| | 阶段矩阵 | 普通保存只触发 SAVE,草稿不触发集合规则,办理只触发 COMPLETE,发布只做协议静态检查 | | SUM 精度 | `99.99/100.00/100.01` 使用 BigDecimal 得到准确结果 | | 集合边界 | 空集合、重复明细、全部必填和至少一行按白名单规则返回业务化错误 | | 条件必填 | 服务端按公式分差要求上级评语;路由/URL/客户端用户/表达式来源不能成为可信必填条件 | | 结果补充字段 | 申诉要求类型/原因,确认调分要求调整分数,普通确认/驳回不误要求其它结果字段 | | 服务端公式 | 加权分和父表总分由服务端计算,子表保存后父表聚合刷新 | | 发布检查 | 公式精度/舍入缺失、依赖失效、公式字段可写配置及集合规则引用损坏均阻断,且不扫描业务记录 | | 唯一办理入口 | PUT 只能保存草稿;POST 一次携带 COMPLETE 数据和业务结果 | | 办理并发 | 相同幂等键同摘要幂等命中,不同摘要冲突;已完成任务不能再次保存/办理 | | 候选状态原子性 | 完整主子表在内存合并、公式重算和校验;校验失败时主表、子表、聚合字段均零写入 | | 命令阶段恢复 | `RESERVED/FORM_SAVED/FLOW_COMPLETED/ACTION_SUCCEEDED/COMPENSATION_PENDING` 只能 CAS 前进,不能由客户端回退或跳阶段 | | 保存后流程失败 | 本地数据已提交但 Flowable 失败时保留 `FORM_SAVED`,相同命令重试不重复保存并继续办理 | | Flowable 响应丢失 | 先查任务/历史确认已完成并收敛到 `FLOW_COMPLETED`,不得第二次办理 | | 最终响应丢失 | 相同键/摘要返回持久化结果;相同键不同摘要及不同键抢占返回确定冲突 | | 节点动作 | 业务状态、申诉、日志和消息只由绑定动作执行,Flow Service 不直接重复写状态 | | 新旧动作互斥 | 节点结果动作与绑定级 APPROVED/REJECTED 回调共存时发布阻断;CANCELED 回调可保留 | | 动作失败 | Flowable 任务保持已完成,补偿台账为 FAILED,页面可观察 | | 补偿上下文 | 固定动作编码/发布版本、流程/任务/节点/结果、对象/记录、规范化变量、原幂等键/摘要和 actionLogId;不保存表单/评分正文 | | 受控重试 | 流程与批量共用 BusinessActionRetryService,对原幂等键、原摘要、原版本和原失败日志 CAS 重试,重复重试不产生第二次逻辑副作用 | | 自动补偿 | 定时与人工并发只有一方成功;退避和最大次数生效,超限进入人工处理状态 | ### 强制回归 - 未配置业务文案时仍显示“同意/驳回”。 - 普通主表流程和未启用节点结果动作时的终态 `APPROVED/REJECTED/CANCELED` 回调行为不回退。 - 集合 `SUM` 与现有聚合公式在空值、精度和舍入上的结果一致。 ## 4. Phase 3:批量查询、快照、幂等和运维 ### P0 | 场景 | 预期 | |------|------| | 可信执行身份 | 预览、手工、Cron 和重试按绑定用户/当前组织实时计算相同数据权限 | | 权威员工来源 | 按 HARD-GATE 选择的已发布员工对象、系统目录适配器或 HR 对象查询;不得直查原始系统表,停用/主岗位/组织/上级口径准确 | | 周期上下文 | 月/季/年、时区和正负偏移生成稳定 key/start/end/label,预览、执行和重试保持一致 | | 身份失效 | 用户停用、组织不可用或权限撤销时失败关闭,零业务写入 | | 源查询白名单 | 未发布字段、非法操作符、任意 SQL 和超上限查询被拒绝 | | 稳定分页 | 配置排序自动追加主键;运行中源数据变化不造成同一源记录重复执行 | | 动作关联查询 | QUERY_RECORDS 按岗位和启用状态加载已发布模板及明细,排序确定且 `expect=EXACTLY_ONE`;零条/多条明确失败,输出可供 FOREACH 使用 | | 预览 | 只返回数量和前 N 条脱敏样例,不写运行/目标业务数据 | | 主子表快照 | 修改源模板后既有任务及明细不变化;单个源记录内主子表失败整体回滚 | | 并发生成 | 动作日志原子占位;相同员工周期只创建一个目标记录 | | 最终唯一约束 | 目标对象未发布复合唯一索引时触发器不能启用;数据库约束可阻止竞态重复 | | 部分失败 | 单条失败不回滚其它记录,运行汇总计数准确 | | 运行上下文冻结 | run 固定触发器/源查询摘要、period JSON、绑定用户/组织 ID 和动作发布版本;设计态配置变化不影响旧 run 重试,但固定身份的账号状态和当前权限仍实时复核 | | 失败重试 | 新增 attempt 日志并关联新 run/原 actionLogId,成功项不重放,逻辑幂等键和动作版本保持不变 | | 分页详情 | 失败明细按 `pageNum/pageSize` 返回,Long ID 为字符串,错误已脱敏 | ### 容量与恢复 - 按第 9 节确认的员工数、指标数、单批大小、最大运行时长和重试次数执行容量验证。 - 运行中断后不得把未执行项记为成功;再次执行依靠幂等和唯一约束安全收敛。 ## 5. Phase 4:动态消息接收人与绩效 E2E ### P0/P1 | 场景 | 预期 | |------|------| | FIELD 单值/多值 | 用户引用字段可解析单个、集合和逗号分隔用户 ID | | 非用户字段 | 普通数字/文本字段不可被设计器选作接收人 | | 空值/非法值 | 默认 FAIL,可显式 SKIP,绝不回退操作人或全员 | | 兼容规则 | OWNER/CREATOR/USERS/ROLES/DEPTS/ALL 行为不变 | | 两类消息配置 UI | 触发器和 Business Action 的 SEND_MESSAGE 都能从字段目录选择 FIELD 接收人,不要求高级 JSON | | 核心流程 | 人工/定时生成 -> 自评草稿/提交 -> 上级评分 -> 确认关闭 | | 申诉流程 | 员工申诉 -> HR 驳回或调分 -> 关闭,结果和消息一致 | | 权限 | 员工、上级、HR 三类账号的数据可见和字段可写范围准确 | | 重复操作 | 重复生成、重复办理、重复回调和补偿重试均无重复业务副作用 | E2E fixture 必须声明 `schemaVersion/fixtureId/namespace`。只有测试加载器和命令已经实现时才允许表述为“可导入”;重复加载只 UPSERT 同一 fixture 管理资源,人工同编码冲突失败关闭,清理仅作用于测试命名空间并输出清单。若 HARD-GATE 未授权加载器,则按说明人工配置并明确记录该限制。报表、企微/飞书/钉钉消息不在验收范围。 ## 6. 计划命令 - 后端插件编译:`mvn -pl forge-framework/forge-plugin-parent/forge-plugin-generator -am compile -DskipTests` - 后端目标测试:按每个 Phase 的新增测试类使用 `mvn -pl ... -Dtest=... test` - 后端聚合构建:`mvn -pl forge-admin-server -am package -DskipTests` - 前端构建:`source ~/.nvm/nvm.sh && nvm use v20.19.0 && NODE_OPTIONS=--max-old-space-size=8192 pnpm build` - Flyway 占位符扫描:`rg -n '\$\{[^}]+\}' forge-server/db/migration` - 文档/空白检查:`git diff --check` 真实命令、测试数量、接口/数据库证据、跳过原因和服务清理统一追加到 `execution-log.md`。