6.8 KiB
Fairness 认证夹具隔离修复(A6 后独立纯测试提交)
日期:2026-09-17
分支:refactor/r01-structure-performance
A6 提交:c6db74a1a8300e1aab8a452fb67909f86861fa43
本轮性质:纯测试修复 —— 生产代码 diff 为 0,Flyway 为 0,OpenAPI 为 0
0. 结论
FairnessMonitoringControllerTest 已不再依赖种子数据、测试执行顺序或共享表清空,
单独运行稳定通过;并新增反证测试锁定该隔离性。
1. 缺陷(A6 独立复验定位)
| 环节 | 事实 |
|---|---|
| 冲突 | 该测试用 token(1L, "ADMIN") / token(2L, "STUDENT"),而 V1_1__seed_data.sql 的种子账号占用 users.id = 1/2/3 |
| 被禁用 | V43__disable_legacy_seed_accounts.sql 把这三行置为 is_active = 0 |
| 夹具缺陷 | TestAuthTokens.writeSession() 仅在 SELECT COUNT(*) FROM users WHERE id = ? 为 0 时 INSERT,不会激活已存在的禁用行 |
| 后果 | AuthSessionService.isSessionActive() 的用户检查短路 → 全部 Token 请求 401 |
| 被掩盖 | 全量顺序下 com.mydreamjob.controller.AuthIntegrationTest 的 @BeforeEach 执行 userRepository.deleteAll(),偶然清掉种子行,夹具随后才补建 active 用户 |
单跑实测(修复前):Tests run: 7, Failures: 6,全部 Status expected:<200|403|400> but was:<401>。
详见 docs/r01-a6-independent-verification-20260917.md §9。
2. 修复方案
选择:让 FairnessMonitoringControllerTest 使用独占用户,而不是修改公共 TestAuthTokens。
理由:公共 helper 若"自动激活已存在的 inactive 用户",会静默复活本应被禁用的账号
(包括生产语义上被 V43 禁用的种子账号),风险远大于收益。
2.1 改动内容
| 项 | 修复前 | 修复后 |
|---|---|---|
| 夹具身份 | userId = 1 / 2(与种子账号冲突) |
独占 ADMIN_USER_ID = 9_310_001L、STUDENT_USER_ID = 9_310_002L |
| 手机号 | 由 TestAuthTokens 隐式生成 "t"+id |
独占 a6fair-admin / a6fair-student |
| 用户来源 | 依赖 TestAuthTokens 的"不存在才插入" |
@BeforeEach 显式插入 is_active = 1 的独占用户 |
| 清理 | 无 | @AfterEach 按精确 ID、按外键顺序删除:auth_tokens → user_roles → users |
@BeforeEach 先执行与 @AfterEach 相同的精确清理再插入,因此对"上轮异常中断残留"具备幂等性,
且从不把任何已存在的 inactive 用户直接激活(是删除后重建自有行)。
2.2 未使用的手段(明确排除)
未改 V43;未改生产认证逻辑;未使用 deleteAll() 清空共享表;未使用 @DirtiesContext 掩盖污染;
未捕获并忽略约束异常;未依赖测试执行顺序;未放宽任何既有 Fairness 断言;未修改公共 TestAuthTokens。
3. 反证测试 FairnessMonitoringFixtureIsolationTest(7 例)
| # | 用例 | 覆盖点 |
|---|---|---|
| 1 | fixtureIdsAreOutsideSeedAccountRange |
夹具 ID 不在种子号段 1/2/3;夹具用户确为 active;未占用种子手机号 |
| 2 | seedRowsInactiveOrAbsent_stillAuthenticates |
种子行 inactive(V43 状态) 与 完全缺失 两种前置下端点均返回 200 |
| 3 | repeatedProvisioningAndRequests_doNotConflict |
连续 3 轮"装配 + 请求"均成功,且不产生重复用户行 |
| 4 | fixtureCycleLeavesSeedRowsUntouched |
完整周期前后种子行逐字段不变(顺序无关的根本保证) |
| 5 | cleanupRemovesOnlyOwnFixtureRows |
清理只删本类行;探针用户及其会话不受波及 |
| 6 | unrelatedUsersAndSessionsUnchanged |
非夹具用户与会话逐字段不变 |
| 7 | publicTokenFixtureDoesNotSilentlyReviveInactiveUser |
TestAuthTokens 对已存在 inactive 用户不激活,该 Token 请求为 401 且 Service 零调用 |
用例 2 会临时快照并按主键原样恢复种子行(try 语义由 @AfterEach 兜底),不新增、不批量重建。
4. 验证矩阵
命令均在 mydreamjob-server/ 下执行;日志位于 docs/acceptance/r01-d4-2-20260916/ff-*.log。
| # | 命令 | 结果 | 日志 |
|---|---|---|---|
| 1 | mvn -Dtest="FairnessMonitoringControllerTest" test |
7 / 7,F=0 E=0 S=0 ✔ | ff-1-standalone.log |
| 2 | mvn -Dtest="FairnessMonitoringFixtureIsolationTest,FairnessMonitoringControllerTest" test |
14 / 14,F=0 E=0 S=0 ✔ | ff-2-isolation.log |
| 3 | Fairness 先跑 ×3(-Dsurefire.runOrder=reversealphabetical) |
13 / 13 ×3 ✔ | ff-3-fairnessfirst-{1,2,3}.log |
| 4 | Auth 先跑 ×3(-Dsurefire.runOrder=alphabetical) |
13 / 13 ×3 ✔ | ff-4-authfirst-{1,2,3}.log |
| 5 | mvn clean verify |
见 §4.1 | ff-5-clean-verify.log |
| 6 | python ..\docs\verify_openapi.py |
176 paths / 214 operations,All checks passed ✔ | — |
顺序说明:surefire 默认
runOrder=filesystem会忽略-Dtest的书写顺序, 因此额外用-Dsurefire.runOrder=reversealphabetical(Fairness 先)与=alphabetical(Auth 先) 强制两个方向,并在日志中逐次核对实际执行顺序(reversealphabetical下scoringmonitoring.FairnessMonitoringControllerTest确在controller.AuthIntegrationTest之前)。runOrder=testorder在本仓库使用的 surefire 3.5.6 中不可用(已实测报错)。
4.1 全量结果
| 项 | 数值 |
|---|---|
| 全量测试总数 | 2278 → 2285(+7:新增反证测试类) |
| Failures / Errors / Skipped | 0 / 0 / 0 ✔ |
| 生产代码 diff | 0 ✔ |
| V1–V45 | 未改动 ✔ |
docs/openapi-rc.json |
未修改 ✔ |
5. 修改文件
mydreamjob-server/src/test/java/com/mydreamjob/scoringmonitoring/FairnessMonitoringControllerTest.java (修改:夹具独占化)
mydreamjob-server/src/test/java/com/mydreamjob/scoringmonitoring/FairnessMonitoringFixtureIsolationTest.java(新增:反证测试)
docs/r01-a6-fairness-fixture-isolation-fix-20260917.md (新增:本报告)
docs/backend-development-roadmap.md (夹具问题关闭记录)
无生产代码、无 Flyway、无 ErrorCode、无 DTO、无接口、无 OpenAPI、无 Filter/Accessor/SecurityConfig 改动。
6. 明确声明
- 未修改任何生产代码,未修改
V43,未修改公共TestAuthTokens夹具。 - 未删除、未放宽任何既有断言;
FairnessMonitoringControllerTest的业务断言逐字保留。 - 未使用
deleteAll()、@DirtiesContext、顺序依赖或异常吞没等掩盖手段。 - 未与 R01-B 混合。
FairnessMonitoringControllerTest 单跑夹具缺陷已通过独立纯测试提交修复; 该测试不再依赖种子数据状态与测试执行顺序。