2026-05-06-REQ-MOD-003.md
2.75 KB
req_id: REQ-MOD-003 date: 2026-05-06 round: 2
reviewer: superpower-code-reviewer
Review: REQ-MOD-003 — round 2
结论
approve
Must-fix
(无;round 1 两条 must_fix 已在 commit 24196599 中修复)
Nice-to-have
- backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java:16 —
org.mockito.ArgumentMatchers仍未使用(round 1 提过,pre-existing;可顺手清掉)。 - backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java:358/375/387 —
(Wrapper<ModuleEntity>) any()强转触发 unchecked 警告,可在类上@SuppressWarnings("unchecked")或就近用ArgumentMatchers.<Wrapper<ModuleEntity>>any()。 - 可选:增加
delete_writesSDeletedByNull_onSoftDelete单元测试,用 ArgumentCaptor 捕LambdaUpdateWrapper解析wrapper.getSqlSet()断言含sDeletedBy=NULL / bDeleted=1 / tDeletedDate=...,把 SET 子句的列覆盖也在单元层钉一遍(目前 SET 列内容仅由 IT 兜底)。 - docs/05-API接口契约.md § REQ-MOD-003 写「40912 响应附 data.references」,spec 未实现;属于已知契约漂移,留给 module-report 时统一对齐。
反例 / 测试覆盖缺口
Round 1 两条 must_fix 均已落实:
-
ModuleServiceImpl.delete()改为moduleMapper.update(null, uw)+LambdaUpdateWrapper.set(BDeleted,true).set(TDeletedDate,now()).set(SDeletedBy,null);eq(BDeleted,false)并发兜底保留;affected==0 → 40421保留。三件套全部由 wrapper 显式声明,绕开iParentId.FieldStrategy.IGNORED副作用。 -
ModuleControllerIT#delete_preservesOtherFields_onChildModule已新增:用自定义字段值(sDisplayType='接口' / sModuleType='AUDIT' / sManageDeptEn='OPS' / bShowPermission=true / sModuleNameZh='待保留中文名' / iSortOrder=7)建 child(parentId),DELETE 后 reload 断言 8 个字段全部保持原值 + bDeleted=true + tDeletedDate 非 null。
单元测试降级合理性:架构改动后 entity 参数为 null,原 ArgumentCaptor 对 entity 字段的断言失去对象;MP 真正写入的 SET 列在 wrapper 内部 SqlSegment,单元层断言列覆盖复杂度高且偏离职责。新 IT 在真实 MySQL 端到端验证「除三件套外其他列保持原值 + iParentId 不被清空」,比 mock 层 ArgumentCaptor 严格得多。verify(moduleMapper).update((ModuleEntity) isNull(), ...) 把"entity 参数必须是 null"这一架构不变量钉死,防止未来误回滚到 entity-driven update。整体是 mock 层小幅放宽 + IT 层显著加强的净增强。
非阻塞遗留:(a) docs/05 § REQ-MOD-003 data.references 描述与实现不一致;(b) 单元测试 ArgumentMatchers 未使用 import;(c) 重复 DELETE 集成层显式用例缺失(间接覆盖足够)。