67837df8d0
- 新增全套考试卷、评估卷、参考答案与考试培训包模板 - 修正slidev培训课件:调整模块标题、链路图缩放,替换工单示例为通用业务对象 - 修正课堂红线表述为证据红线,将小组作业调整为个人作业要求 - 新增权限、状态流转、审计日志、看板指标四类可复用业务规则块 - 整理AI工程技能交付包,迁移旧资产至客户专属交付包并统一术语 - 新增考试输出模板与TRAE使用记录文档
211 lines
12 KiB
Markdown
211 lines
12 KiB
Markdown
# 模块 13:历史代码治理、类型契约与测试补齐
|
|
|
|
<div class="mt-6 text-sm">
|
|
|
|
Rule、Skill、Agent 和 MCP 解决的是“如何沉淀判断”。
|
|
|
|
回到真实项目,历史代码治理还需要回答:哪些结构可以调整、哪些行为必须保持、类型是否真的表达了接口契约,以及测试到底覆盖到哪里。
|
|
|
|
</div>
|
|
|
|
<div class="grid grid-cols-6 gap-3 mt-8 text-xs">
|
|
<div class="p-3 rounded-xl bg-blue-500/10 border border-blue-500/30">职责结构</div>
|
|
<div class="p-3 rounded-xl bg-emerald-500/10 border border-emerald-500/30">行为基线</div>
|
|
<div class="p-3 rounded-xl bg-amber-500/10 border border-amber-500/30">命令模型</div>
|
|
<div class="p-3 rounded-xl bg-purple-500/10 border border-purple-500/30">类型契约</div>
|
|
<div class="p-3 rounded-xl bg-red-500/10 border border-red-500/30">测试矩阵</div>
|
|
<div class="p-3 rounded-xl bg-cyan-500/10 border border-cyan-500/30">断言边界</div>
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:第五天最后一个模块把前面的资产方法落回历史代码治理。前面已经讲过 Rule、任务上下文契约、Skill、Agent 和 MCP 如何承载稳定判断;这里专门处理远程原大纲中尚未展开的重构、类型和测试主题。
|
|
|
|
仍然使用当前公务用车模块作为证据来源。重点不是让大家现场背一套重构套路,而是建立可审查的判断:哪些结构可动、哪些状态行为不能动、跨端类型怎样核验、测试如何证明副作用。
|
|
-->
|
|
|
|
---
|
|
|
|
# 派车重构的候选职责结构
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
当前 `assign` 保持事务编排入口,候选拆分只调整内部职责,不改变 Controller、接口或写入顺序:
|
|
|
|
```text
|
|
assign(vo) @Transactional
|
|
|- 校验申请:存在、已审批、未重复派车
|
|
|- 校验车辆:存在、可用、时间不冲突
|
|
|- 校验司机:按 needDriver 决定必填、可用、时间不冲突
|
|
|- 创建派车任务:写入申请、车辆、司机、计划时间与状态
|
|
`- 预占车辆:AVAILABLE -> RESERVED
|
|
```
|
|
|
|
| 可调整的内部边界 | 不能借拆分改变的行为 |
|
|
|---|---|
|
|
| 私有校验方法、局部命名、组装对象的位置 | 事务边界、拒绝顺序、接口字段、派车与车辆的写入语义 |
|
|
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:这页补上远程大纲中的重构实操目标。我们不在课件中伪造一份已经合入的重构 Diff,而是依据当前 assign 的真实代码给出候选职责结构。它仍保留 assign 作为事务编排入口,按申请、车辆、司机、任务创建和车辆预占分段。
|
|
|
|
关键不在于拆出几个方法,而在于拆分后外部行为不变:拒绝仍发生在写入前,接口字段不变,派车任务和车辆预占仍在同一事务里。这个结构是 TRAE 可以协助形成并接受审查的最小重构目标,而不是让模型自作主张改 Controller、页面或数据库。
|
|
-->
|
|
|
|
---
|
|
|
|
# 用行为基线验收无损重构
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
`assign` 的当前源码可先整理为行为基线;重构后的代码和测试都应逐项回到这张表。
|
|
|
|
| 输入条件 | 预期结果 | 允许的写入 |
|
|
|---|---|---|
|
|
| 申请不存在、未完成或已派车 | 拒绝派车 | 无派车任务、无车辆状态变更 |
|
|
| 车辆不存在、不可用或时间冲突 | 拒绝派车 | 无派车任务、无车辆状态变更 |
|
|
| 需要司机但未提供,或司机不可用/冲突 | 拒绝派车 | 无派车任务、无车辆状态变更 |
|
|
| 所有前置条件满足 | 创建 `DISPATCHED` 派车任务 | 车辆由 `AVAILABLE` 变为 `RESERVED` |
|
|
|
|
</div>
|
|
|
|
<div class="mt-6 p-3 rounded-xl bg-emerald-500/10 border border-emerald-500/30 text-sm">
|
|
“无损”不是代码未报错,而是每个拒绝路径和成功副作用仍与基线一致。
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:重构验收不能只看编译通过或页面能打开。assign 的原始代码已经给出四类行为:申请不符合条件时拒绝,车辆不符合条件时拒绝,司机条件不满足时拒绝,所有条件满足才创建已派车任务并预占车辆。
|
|
|
|
这张行为基线把远程大纲中的“行为一致性”和“测试缺口”连接起来。重构后的每一个测试都要能回到其中一行,特别是三类拒绝路径都不能产生派车任务或车辆状态变更。这样才能判断结构整理是否真正无损。
|
|
-->
|
|
|
|
---
|
|
|
|
# 类型治理要分开命令、实体与展示模型
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
派车模块已有一组可对照的模型边界:
|
|
|
|
| 模型 | 当前字段范围 | 应承担的职责 |
|
|
|---|---|---|
|
|
| `OfficialVehicleDispatchVo` | `applyId`、`carId`、可选 `driverId`、`remark` | 派车命令的唯一输入 |
|
|
| `OfficialVehicleDispatch` | ID、调度人、时间、状态、取消原因等 | 服务端持久化与列表展示结果 |
|
|
| 前端 `OfficialVehicleDispatchVo` | 与派车命令相同的四类字段 | 提交时只发送用户可提供的内容 |
|
|
| 前端 `OfficialVehicleDispatch` | 读取列表中的状态、时间和调度人等 | 展示与操作条件判断 |
|
|
|
|
</div>
|
|
|
|
<div class="mt-6 p-3 rounded-xl bg-blue-500/10 border border-blue-500/30 text-sm">
|
|
命令类型不是实体类型的 `Partial`:状态、时间和操作人不应由派车表单决定。
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:类型治理还要区分同一业务对象在不同方向上的模型。当前后端的 OfficialVehicleDispatchVo 只有派车时需要提交的四类字段;实体则多了系统生成的调度人、时间、状态和取消原因。前端也分别定义了命令模型和展示模型,提交时显式组装四个字段。
|
|
|
|
这个对照说明了类型抽取的正确目标:不要让页面用 Partial 实体随意提交状态、时间或操作人。命令模型描述“用户能请求什么”,实体或展示模型描述“系统已经产生什么”。这比单纯增加 interface 更能防止重构后字段权限漂移。
|
|
-->
|
|
|
|
---
|
|
|
|
# 类型差异必须形成可执行的核验用例
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
审批结果和申请状态的定义差异,不能只记录在问题单中,应转换为可验证的契约。
|
|
|
|
| 核验对象 | 输入或观察值 | 需要确认的结论 |
|
|
|---|---|---|
|
|
| 审批命令 | `pass`、`reject`、`PASS`、`REJECT` | 哪些值能被接口接受;拒绝时返回什么语义 |
|
|
| 审批表单 | 单选组件实际提交的 `result` | 页面提交值是否与接口契约一致 |
|
|
| 申请状态 | `1`、`"1"` 及接口返回值 | 前端渲染和状态判断使用的唯一表示 |
|
|
| 类型定义 | 联合类型、表单选项、后端常量 | 三处是否指向同一组允许值 |
|
|
|
|
</div>
|
|
|
|
<div class="mt-6 p-3 rounded-xl bg-amber-500/10 border border-amber-500/30 text-sm">
|
|
类型契约完成的标准是“能执行的接受与拒绝用例”,不是文档里多了一行枚举。
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:上一页发现了审批结果和状态值的跨端定义差异,这一页进一步说明怎样处理。正确的产出不是写一句“统一大小写”,而是形成可执行的核验用例:四种审批值分别怎样处理,页面实际发出的是什么,状态在接口和页面中的唯一表示是什么,类型定义、表单选项和后端常量是否一致。
|
|
|
|
这样一份类型契约可以交给 TRAE 生成检查项或测试草案,也可以作为 Review 的依据。最终仍要以 API 或集成测试确认真实请求的接受和拒绝语义,不能仅根据类型声明下结论。
|
|
-->
|
|
|
|
---
|
|
|
|
# 取消派车的测试用例应覆盖状态与副作用
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
| 场景 | 期望行为 | 当前证据状态 |
|
|
|---|---|---|
|
|
| `cancelReason` 全空白 | 立即拒绝,不访问后续依赖 | 已有 Service 单测 |
|
|
| 派车任务不存在 | 拒绝,不更新派车或车辆 | 待补 |
|
|
| 派车状态不是 `DISPATCHED` | 拒绝,不释放车辆 | 待补 |
|
|
| 任务可取消且车辆存在 | 记录取消原因,派车变 `CANCELLED`,车辆变 `AVAILABLE` | 待补 |
|
|
| 任务可取消但车辆记录缺失 | 派车仍完成取消,避免空指针 | 待补,当前源码有空值保护 |
|
|
|
|
</div>
|
|
|
|
<div class="mt-6 p-3 rounded-xl bg-purple-500/10 border border-purple-500/30 text-sm">
|
|
测试用例的粒度应跟随状态与副作用,不以“覆盖了 cancel 方法”作为完成标准。
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:远程大纲中的测试用例生成,应针对当前 cancel 方法的真实分支。现有服务单测只覆盖了空白原因。接下来至少还要覆盖派车任务不存在、状态不允许、正常取消且车辆存在、以及车辆记录缺失这五种场景。
|
|
|
|
最后一种很容易漏掉,但源码明确用 if 判断保护了车辆为空的情况。因此它既是行为分支,也是有价值的回归点。每个用例要同时写清拒绝或成功结果,以及派车和车辆是否应发生写入,避免只断言异常消息或方法被调用。
|
|
-->
|
|
|
|
---
|
|
|
|
# 断言要与被测层级匹配
|
|
|
|
<div class="mt-5 text-xs">
|
|
|
|
| 被测层级 | 当前可见证据 | 应断言什么 | 不能替代什么 |
|
|
|---|---|---|---|
|
|
| Controller | Mockito 验证 `cancel` 的委派与结果消息 | 接口是否交给正确的 Service 参数 | Service 内部状态和持久化行为 |
|
|
| Service 拒绝路径 | 空白原因抛出异常 | 不满足条件时无后续写入或资源释放 | 正常取消的双对象更新 |
|
|
| Service 成功路径 | 当前尚无定向单测 | 派车状态、取消原因、车辆状态及更新次数 | 前端实际请求载荷 |
|
|
| API / 集成层 | 当前尚无契约验证记录 | 前后端值、权限、序列化与错误响应 | 未执行环境的全链路结论 |
|
|
|
|
</div>
|
|
|
|
<div class="mt-6 p-3 rounded-xl bg-red-500/10 border border-red-500/30 text-sm">
|
|
Controller Mock 测试通过,不等于业务状态机已经被测试。
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:最后一页补的是测试质量判断。当前 Controller 测试使用 Mockito 验证委派关系和结果消息,这正是 Controller 层应保护的内容;它不能替代 Service 层的状态和持久化验证。现有 Service 空白原因测试证明了一个拒绝路径,但还没有覆盖正常取消的双对象更新。
|
|
|
|
因此,TRAE 生成测试时要先说明被测层级和断言对象:Controller 看参数转交,Service 看规则和副作用,API 或集成层看真实请求、序列化、权限与错误响应。把这三类测试混在一起,最常见的结果就是 Mock 测试通过,却误以为业务状态机已经安全。
|
|
-->
|
|
|
|
---
|
|
|
|
# 从案例到可执行资产
|
|
|
|
<div class="mt-8 text-lg">
|
|
案例提供事实;资产保存判断;重构守住行为;类型表达契约;测试证明副作用;MCP 将外部能力纳入同一套边界。
|
|
</div>
|
|
|
|
<div class="grid grid-cols-8 gap-2 mt-8 text-xs">
|
|
<div class="p-3 rounded-xl bg-blue-500/10 border border-blue-500/30">事实</div>
|
|
<div class="p-3 rounded-xl bg-emerald-500/10 border border-emerald-500/30">Rule</div>
|
|
<div class="p-3 rounded-xl bg-amber-500/10 border border-amber-500/30">任务契约</div>
|
|
<div class="p-3 rounded-xl bg-purple-500/10 border border-purple-500/30">Skill</div>
|
|
<div class="p-3 rounded-xl bg-red-500/10 border border-red-500/30">Agent</div>
|
|
<div class="p-3 rounded-xl bg-cyan-500/10 border border-cyan-500/30">MCP</div>
|
|
<div class="p-3 rounded-xl bg-orange-500/10 border border-orange-500/30">类型</div>
|
|
<div class="p-3 rounded-xl bg-slate-500/10 border border-slate-500/30">测试</div>
|
|
</div>
|
|
|
|
<!--
|
|
逐字稿:第五天从真实案例开始,最终交付不止是一组提示词或一处功能改动。案例和源码提供事实,Rule、任务上下文契约、检查单和 Skill 保存判断,Agent 固化职责,MCP 管理外部能力;历史代码重构用行为基线限制改动,类型契约消除跨端歧义,测试证明状态和副作用。
|
|
|
|
因此,AI 工程资产不是单独存放的 Markdown 文件,而是一组能支持真实工程判断、修改和验证的契约。第六天将把这些资产放入 PR、Git、CI 和变更证据链中,处理工程协作与质量闭环。
|
|
-->
|