You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7.3 KiB
7.3 KiB
账号注销测试夹具隔离修复报告
日期:2026-09-17
分支:refactor/r01-structure-performance
基线 HEAD:d5c37128e84b4fc83bf5334254dd8efeb88ccf64
性质:纯测试修复 —— 生产代码、Flyway、配置与接口零改动
1. 结论
AccountDeletionControllerTest与关联测试组合的既有交叉污染已消除;修复后两种执行顺序各 5 次全部 F=0 / E=0 / S=0。
2. 稳定复现(修复前)
致冲突组合(连续运行 5 次,5/5 稳定复现):
mvn -Dtest="*Deletion*Test,*Verification*Test,*Risk*Test,*Report*Test,*Block*Test,
*Notification*Test,*Recommendation*Test,*RequestContext*Test,*RequestId*Test" test
5 次运行全部失败于同一位置:
AccountDeletionControllerTest.lazyTransition_firstGet_returnsCompleted_andConsistent:228
-> createUser:75
DataIntegrityViolation: Unique index or primary key violation:
USERS(PHONE) = '930000000'
诊断结论(逐项回答)
| 问题 | 结论 |
|---|---|
谁先插入 phone='930000000' |
com.mydreamjob.common.logging.RequestContextMigrationIntegrationTest(HEAD 既有类)。其 @BeforeEach 用 AtomicLong(930_000_000L) 创建 user |
| 冲突发生在哪个方法 | AccountDeletionControllerTest#createUser:75(由 lazyTransition_firstGet_returnsCompleted_andConsistent:228 调用) |
| 共享 H2 数据库名 | integrationdb(jdbc:h2:mem:integrationdb;MODE=MySQL;DB_CLOSE_DELAY=-1)—— 同一 JVM 内所有 @SpringBootTest 共享 |
| static 计数器何时重置 | 不重置 —— PHONE 为 per-class static,类加载时初始化为 930_000_000;冲突不是计数器重置所致,而是号段被残留记录占用 |
| 未清理的记录 | users(phone=930000000);user_roles 随 users 级联删除 |
根因链
- 号段撞车:
common/logging/RequestContextMigrationIntegrationTest与deletion/AccountDeletionControllerTest都使用基数930_000_000 - 污染源不清理:前者
@AfterEach只清RequestContextProbe与MDC,不删 users → 每个测试方法残留 1 条930000000+N - 受害者删除失败:后者的
@AfterEach用userRepository.deleteAll()(全表删除),会因其他测试类残留 user(被notifications/offers/resume_versions等无 CASCADE 的外键引用)而失败 → 自身 user 也未删净 - 执行顺序:诊断运行中
common.logging.RequestContextMigrationIntegrationTest排在第 6 位、AccountDeletionControllerTest排在第 13 位 → 前者残留必然影响后者
与 A2/A3 的关系(如实记录)
A2/A3 新建的测试类均不创建 user,故无污染:
common/r01a2/RequestContextMigrationIntegrationTest:无AtomicLong、无userRepository注入- A3 的三个测试类:均使用
@MockBean UserRepository(不实际写库)
该缺陷完全存在于基线(污染源文件为 HEAD 既有),与 A2/A3 无关;此前用 HEAD 隔离 worktree 的归因结论正确。
同号段还有
candidatescore/CandidateScoringClockBoundaryIntegrationTest,但其标注@Transactional(每方法自动回滚)→ 不残留,无风险。
3. 修复内容
3.1 common/logging/RequestContextMigrationIntegrationTest.java(污染源)
| 改动 | 内容 |
|---|---|
| 号段独占 | 930_000_000L → 986_000_000L(已确认全仓未占用) |
| 清理 | @AfterEach 增加:按自身 studentId 精确删除本测试创建的 user(findById(...).ifPresent(delete)),并补 javadoc 说明隔离原因 |
3.2 deletion/AccountDeletionControllerTest.java(受害者)
| 改动 | 内容 |
|---|---|
| 号段独占 | 930_000_000L → 987_000_000L(已确认全仓未占用) |
| 记录归属 | 新增 List<Long> createdUserIds,createUser() 登记每个自建 userId |
| 精确清理 | @AfterEach 由 deleteAll()(整表)改为按本测试记录删除:account_deletions(按 userId)→ users(级联 user_roles),各步 flush(),遵循外键顺序;@BeforeEach 清空记录 |
| 防掩盖断言 | createUser() 内先断言该号在共享库中不存在,存在即抛出可读错误(暴露上轮清理失效),而不是被唯一键异常吞掉 |
未使用:未改唯一约束、未捕获忽略 DataIntegrityViolationException、未用 @DirtiesContext、未清空整表、未 DELETE FROM users 无条件删除、未 sleep、未放宽任何业务断言、未依赖测试执行顺序。
3.3 新增反证测试 deletion/AccountDeletionFixtureIsolationTest.java(5 例)
| 反证 | 断言 |
|---|---|
| 1 | 同一 Spring 上下文内连续创建 5 个夹具不冲突且 ID 不重复 |
| 2 | 注销记录写入后,按本测试路径清理 → account_deletions / users / user_roles 残留均为 0 |
| 3 | 变异探测:预置同号记录(等价于"上轮未清理")→ 防掩盖断言必须失败并检出该号,证明残留不会被静默吞掉 |
| 4 | 独占号段 987_000_000 在测试开始前为空(不与任何他类重叠) |
| 5 | 清理精确到本测试记录:预置的"他类"记录必须保留,证明不是整表删除 |
4. 验证结果
4.1 两种执行顺序各 5 次
| 组合 | 结果(5 次) | |
|---|---|---|
| 顺序 A | *Deletion*Test,*RequestContext*Test,*RequestId*Test |
95/95,F=0 E=0 S=0 ×5 ✔ |
| 顺序 B | *RequestContext*Test,*Deletion*Test,*RequestId*Test |
95/95,F=0 E=0 S=0 ×5 ✔ |
(修复前该组合稳定失败 5/5;修复后 10/10 全绿)
4.2 单类与反证
| 命令 | 结果 |
|---|---|
mvn -Dtest="AccountDeletionControllerTest" test |
14 / 14 ✔ |
mvn -Dtest="AccountDeletionFixtureIsolationTest,AccountDeletionControllerTest" test |
19 / 19(5 反证 + 14 原)✔ |
4.3 全量
| 命令 | 结果 |
|---|---|
mvn clean verify |
2225 / 2225,Failures=0、Errors=0、Skipped=0,BUILD SUCCESS(≥ 2220 ✔) |
python docs\verify_openapi.py |
176 paths / 214 operations,All checks passed ✔ |
较修复前(2220)新增 5 个测试,全部为反证测试。
4.4 边界核验
| 项 | 结果 |
|---|---|
生产源码 git diff --stat -- src/main/ |
空(零改动)✔ |
| V1–V45 迁移 | 零修改 ✔ |
| Flyway / 配置 / 接口 | 零改动 ✔ |
GlobalExceptionHandler.java |
仍为工作区 stat 标记(内容零差异),未处理 ✔ |
| Docker | 未操作 ✔ |
| 是否进入 A4 | 否 ✔ |
5. 精确修改文件
修改(2)
mydreamjob-server/src/test/java/com/mydreamjob/common/logging/RequestContextMigrationIntegrationTest.java
mydreamjob-server/src/test/java/com/mydreamjob/deletion/AccountDeletionControllerTest.java
新增(1)
mydreamjob-server/src/test/java/com/mydreamjob/deletion/AccountDeletionFixtureIsolationTest.java
文档(1)
docs/account-deletion-test-isolation-fix-20260917.md
6. 提交
提交信息:test: isolate account deletion controller fixtures
(精确暂存上述测试文件与报告,敏感扫描后独立提交;推送当前 R01 功能分支)
账号注销测试夹具隔离修复完成;测试交叉污染已消除,生产代码零改动。