Project

General

Profile

CR #201 » TRP-004_覆蓋率提升總結報告.md

內容更新:內部稱謂去識別化(2026-10-18) - Redmine Admin, 10/18/2026 05:32 AM

 

TRP-004 覆蓋率提升總結報告

文件編號:TRP-004|性質:測試類——總結報告(GOV-001 §6.6)
權威來源:TRP-003_覆蓋率提升計畫(v3.10,含全部批次之逐批記錄)
量測工具:JaCoCo(CSP-005 §4)|量測範圍:backend/services/*(17 個領域服務)
報告日期:2026-10-06(v1.7)|對應交接編號:#A-166~#A-222


1. 摘要

指標 起點(2026-10-02) 終點(2026-10-06) 目標 判定
行覆蓋 53.7% ★★★ 90.92%(11,397/12,535) 80% ✅ 達成(超出 1,369 行)
分支覆蓋 46.8% ★★★ 71.64%(2,607/3,639) 70% ✅ 達成(★ #A-210 達標)
測試數 1,063(#A-183 時) 1,478(+415) — —
失敗/錯誤 0/0 0/0 0 ✅
略過 2 1(★ 見 §7.1) 0 ⚠️

⚠️ 口徑聲明(★ 必讀,2026-10-06 #A-216/#A-218/#A-219/#A-220 更新):本報告 §3~§7 之數字為
backend/services/*(17 個領域服務) 之口徑。
★★ 另有「全 backend」口徑(backend/**=17 服務 + 8 個 platform/ 共用模組)——
★★★ 該口徑於 #A-222(批次 20-f)後為 行 91.94%/分支 76.18%——兩項門檻皆已達標。
★ 兩者皆正確,僅範圍不同;★ platform/ 8 模組:行 69.4% → 97.17%、
分支 59.1% → 92.99%
(未覆蓋 745 → 69 行、402 → 30 條分支)。
★★ WBS 5.37(platform/ 8 模組)已結案(★ 8/8 模組完成)。
★★ 併記:批次 20-d 於補測時揭露並修補一個真缺陷(CR-042:JwtAuthFilter 之 401 路徑必拋 NPE)。

★★★ 兩項目標皆已達成——行覆蓋自 53.7% 提升至 90.92%(淨增 37.22 個百分點、
+4,664 行:6,733 → 11,397);★ 分支覆蓋 46.8% → 71.64%(門檻 70%)。
★ 本報告 v1.0~v1.1 記錄至批次 13(82.42%);★ 批次 14~17-d 之完整記錄見
TRP-003 §6.11.21~§6.11.30
(★ 本報告不再逐批複製,避免雙份真實來源)。


2. 量測方法(可重現)

# ① 全量測試(★ 驗收一律全量,單一類別之數字不可與基線比)
source ops/local/env.sh; cd backend && ./gradlew test --continue

# ② 逐服務彙總行覆蓋(JaCoCo HTML 之 <tfoot> Total 列)
#    抓 backend/services/*/build/reports/jacoco/test/html/index.html
#    欄位:missedLines(第 7 欄) / lines(第 8 欄)
  • ★ 計分口徑:以 JaCoCo 之「行(Lines)」 為準(與 CSP-005 §4 之門檻一致)。
  • ★ 排除計法假象:已確認全庫 @Disabled 為 0;未以 @Generated/lombok 等
    手段排除任何程式碼。
  • ★ 分母 12,535 行為 17 個服務之 JaCoCo 行數總和(非檔案行數)。

3. 逐服務結果

服務 行覆蓋 服務 行覆蓋
merchant-service ★★ 98.9% pricing-service 93.4%
dispute-service ★★ 96.5% card-service 92.4%
migration-service ★ 92.1% product-service ★ 91.9%
posting-service 86.8% clearing-service 86.0%
notification-service 85.7% rewards-service 85.7%
payment-service 85.0% installment-service 82.3%
limit-service 80.7% statement-service 76.7%
report-service 74.1% authorization-service ⚠️ 61.6%
party-service ⚠️ 59.6%

★ 15/17 服務 ≥ 74%;★★ 14 服務 ≥ 80%(v1.0 時為 10)。
⚠️ 兩個服務仍低於 62%(party/authorization)——見 §7.3。


4. 執行批次總表

批次 範圍 交接 全服務行覆蓋
(起點) — — 53.7%
B1 limit jdbc(首發) #A-166~#A-168 54.7%
W1/W2 installment/pricing/dispute/merchant/payment jdbc #A-170~#A-179 62.2%
B2 rest 層 @WebMvcTest——16 服務/25 類別/130 測;★ 併回頭補 AuthorizationController 76 行 → 0 #A-180~#A-183 64.1%
CR-041 B2 揭露之請求層三項發現(1 項經查證更正為非缺陷) #A-187 —
W3 statement/posting jdbc #A-188/#A-189 67.0%
W4 rewards/card jdbc #A-190/#A-191 70.3%
批次 1 B4-a 領域分支(party.Party/rewards.PointsAccount) #A-193 71.4%
批次 2 B3-b-1 scheduler 層 88/88 → 100% #A-194 72.1%
批次 3 authorization 之 JdbcAuthorizationRepository(162 行,全庫最大單一缺口) #A-195 73.7%
批次 4 party jdbc #A-196 74.4%
批次 5 clearing jdbc #A-197 75.2%
批次 6 limit 之兩個付款投影(★ 併結案 WBS 5.13) #A-198 75.7%
批次 7 notification jdbc #A-199 76.6%
批次 8 report jdbc(★★ 雙容器:Oracle + PostgreSQL) #A-200 77.5%
批次 9 migration jdbc(★ +31.6 pp,單服務最大跳幅) #A-201 78.6%
批次 10 product jdbc(★ jdbc 套件整體 100%) #A-202 79.1%
批次 11 payment/installment/report/dispute/merchant jdbc 收尾(★ 併解跨 schema 略過項) #A-203 79.74%
批次 12 outbox 套件(KafkaEventPublisher/OutboxRelayScheduler/OutboxRelayConfig)——limit/payment #A-204 ★★ 80.18%
批次 13 ★★ outbox 橫向複製至其餘 10 服務(分 13-a/13-b 兩批執行) #A-205 ★★ 82.42%

5. 方法論:本計畫之三個關鍵洞察

5.1 ★★ 策略不是「多寫單元測試」,而是「把真機驗證自動化」

根因:本專案之人工真機驗證為 curl + SQL,不進 JVM →
對 JaCoCo 之貢獻恆為 0(★ 已查證:全庫 @Disabled 為 0;
JdbcLimitRepository 被測試提及 0 次)。

缺口分布(#A-183 前):63.8% 集中於「與外部世界接觸的層」
(jdbc 40.8%/rest 6.9%/outbox·messaging·client·storage·scheduler 16.0%),
業務邏輯層已健康(application 73.6%/model 80.8%)。

→ 解法:以 Testcontainers 把人工驗證自動化——一舉兩得
(覆蓋率 + 人工驗證變可回歸),且不違反禁 mock。

5.2 ★★ 配方(TRP-003 §6.4;已於 17 服務、逾 300 測驗證)

純 JUnit 5 + 手動 JdbcTemplate(不用 @JdbcTest 切片)→
Testcontainers 一次性 Oracle(gvenzl/oracle-free:23-slim)→
Flyway 於 @BeforeAll(★ 附帶驗證「遷移可在乾淨 schema 套用」)→
@BeforeEach 明確 DELETE(★ 依 FK 反向清理)→
★ 條件類查詢造 3~4 種近似情境、僅 1 種應命中(防假綠)。

5.3 ★★★ 「jdbc 與 model 之協同效應」

以真實 repository 為協作者,測試路徑會順帶走過領域層之
reconstitute/存取子/狀態轉移方法——★ 故 jdbc 測試之實際增益
常大於該類別本身之行數(例:批次 3 之 JdbcAuthorizationRepository
162 行 → 全服務 +195 行)。


6. ★★ 真機反駁我方假設/我方錯誤——彙總(13 項;★ 全為我方之錯,非程式缺陷)

★ 依 TRP-003 之編號,正式記為「真機反駁」者至 第七次(#A-202);
下表併收「真機反駁」與「我方算錯」(如 #A-203 之群組數漏計)——皆為我方之誤。

# 批次 我方假設 實測結果
1 #A-168 outstandingMinor 之語意 誤解欄位語意
2 #A-189 「同冪等鍵、不同歸戶」可造兩列 TRANSACTIONS.idempotency_key 為全域 UNIQUE → 至多 1 筆
3 #A-190 可把 POINTS_EXPIRY_BUCKETS.points 更新為 0 CHECK (points > 0) → ORA-02290
4 #A-191 save 會寫入全部欄位 card_id 不在 INSERT 內(CR-020 F1)
5 #A-191 Timestamp.from(instant) 保留 offset offset 遺失(變成 session 時區)
6 #A-199 OracleRawId.toUuid 對壞長度回 null 拋 IllegalStateException(fail-closed)
7 #A-200 ReportJob 可自 QUEUED 直接完成 狀態機為 DAG(complete/fail 皆要求 RUNNING)
8 #A-201 三個遷移列舉為獨立類別 皆為巢狀列舉(編譯失敗 15 處)
9 #A-201 表名為 LEGACY_ACCOUNTS 實為 legacy_account_mappings(★ 只讀類別名會猜錯)
10 #A-202 樂觀鎖衝突可用「已落後物件 + withUpdated」造 +1 恰好補成「DB 現行 + 1」→ 反而成功
11 #A-202 錯誤碼字面值為常數名之底線形式 實為連字號 CC-PLT-5000
12 #A-203 容器 app user 無 DBA → 跨 schema 測試只能略過 映像之初始化腳本係以 sysdba 執行 → 可測
13 #A-203 區間內群組數為 3 實為 4(漏計一個群組)

★★★ 共同根因:我沒有先查證。
★★ 先查證之順序:表名/欄位 → 列舉位置 → 方法簽章 → 執行環境 → 才寫測試。
★ 每一次反駁都已回寫技能(cardcore-jdbc-integration-test 之「陷阱 1~8」)。


7. 誠實揭露

7.1 唯一之略過測試(1 個)

statement-service 之 StatementPdfRealMachineTest——★ 需真實物件儲存(MinIO/S3),
於容器環境不略過、直接失敗之設計尚未建立。如實記錄。

7.2 ✅ 分支覆蓋已達標(★ 本節於 v1.2 更正;原記「未達標」已過期)

口徑 分支覆蓋 門檻 判定
17 服務 ★ 71.64%(2,607/3,639) 70% ✅
★ 全 backend ★★ 76.18%(3,522/4,623) 70% ✅(超出 286 條)

★ 歷程:46.8% → 63.78% → 64.33% → 66.67% → 69.80% → 70.43% → 70.73% → 71.64% → 72.12% → 73.35% → 74.86% → 76.18%。
★ 關鍵貢獻:party application 層(+189 行 → +114 條分支)/
bff-web(批次 20-b,+114 條分支)/api-gateway(批次 20-c,+57 條分支)/
common-security(批次 20-d,+70 條分支)/common-spring(+32)/common-saga(+29)。
★★ 未以假測試湊數——未覆蓋者皆為不可達之防禦分支,逐條如實記錄
(見 TRP-003 §6.11.33/§6.11.34 之殘餘清單)。

7.3 ✅ 兩個原低覆蓋服務已大幅改善(★ 本節於 v1.2 更正)

服務 v1.1 記載 現況 主要增益來源
authorization-service 61.6% ★ 83.2% messaging(+144)/client(+134)
party-service 59.6% ★★ 91.5% application(+189 行,單服務最大改善)

7.4 殘留缺口全貌(★ v1.2 重算:服務側 1,138 行未覆蓋;v1.1 為 2,153)

層 未覆蓋行 佔比
application 508 44.6%
infrastructure 431 37.9%
domain 177 15.6%
interfaces 22 1.9%

未覆蓋最多之套件(前 10):

未覆蓋/總行 服務 套件
35/78 posting posting.application
33/35 installment inst.application
32/32 authorization auth.application
28/28 party party.infrastructure.messaging
28/28 clearing clr.infrastructure.jdbc
28/28 authorization auth.infrastructure.limit
26/166 notification notif.application
25/25 installment inst.application
25/25 authorization auth.infrastructure.jdbc
24/35 statement stmt.application

★ outbox/messaging/client/storage/application(四子批)皆已完成——
★ 低成本紅利已耗盡。
★ 下一級:★ WBS 5.37 之餘 6 個平台模組(api-gateway 166/common-security 104/
common-spring 67/common-saga 36/common-domain ✅/common-batch ✅)
與各服務之 application 層殘餘(posting 35/installment 33/authorization 32…)。


8. 結論與建議

  1. ★★ 行覆蓋目標(80%)已達成並超額——★ 17 服務 90.92%;
    ★★★ 「全 backend」口徑亦達 89.82%(#A-218)。且未以任何假測試/mock 湊數——
    全庫掃描器(scan_scaffold/scan_mockdata/scan_faketest/validate_sql/
    validate_mermaid/gen_service_skeleton --check/verify_versions)全數通過。
  2. ★ 測試數自 1,063 增至 1,478(+415;服務側),0 失敗/0 錯誤;
    ★ 略過數 2 → 1(跨 schema 略過項已解)。★ 另加 platform/ 之 109 測(批次 20-a 47 + 20-b 62)。
  3. ✅ 分支覆蓋(70%)已達標——★ 17 服務 71.64%、★★ 全 backend 72.12%
    (★ 本節於 v1.4 更正;原記「未達標」係 v1.0 之舊狀態)。
  4. ★ outbox 套件已全數完成(12/12 服務 100%,合計 +336 行);
    ★ messaging/client/storage/application(四子批)亦已完成——
    ★ 低成本紅利已耗盡;下一級成本明顯上升。
  5. ★ 建議後續批次(依「每行覆蓋之成本」排序):
    ① ★ JdbcSagaStore 之 Oracle 整合測試(★ common-saga 餘 16 行;★ 已有
    JdbcSagaStoreIntegrationTest,需容器)+ common-spring 之
    ConstraintViolationException 分支(★ 需引入 Bean Validation 實作);
    ② 各服務 application 層殘餘(posting 35/installment 33/authorization 32/
    notification 26/statement 24);
    ③ infrastructure 之殘餘(party.messaging 28/clearing.jdbc 28/auth.limit 28)。
  6. ★ 方法論沉澱:本計畫之三項可複用技術已回寫技能——
    ★ 「結構簽章抽取」先於橫向複製(去註解後比對 API,非目視 diff);
    ★ 容器初始化腳本以 sysdba 執行(/container-entrypoint-initdb.d/*.sql),
    可建跨 schema 之前置條件;★ 樁 HTTP 伺服器(JDK 內建 HttpServer,零相依)
    模擬同儕/外部服務——★ 受測物與協作者皆為真實物件,非 mock。
  7. ★ 文件為單一真實來源:逐批之完整記錄見 TRP-003 §6.11.1~§6.11.33;
    逐項交接見 HANDOVER §3.A 之 #A-166~#A-218。

9. 修訂記錄

版本 日期 修訂內容
1.7 2026-10-06 ★★★ 批次 20-e/20-f 納入(#A-221/#A-222)——★★★ WBS 5.37 結案(8/8 模組):★★ common-spring 行 → 94.9%/分支 → 85.3%(+40 行/+32 分支);★★ common-saga 行 → 95.4%/分支 → 87.5%(+17 行/+29 分支)。★★★ platform/ 8 模組:行 69.4% → 97.17%、分支 59.1% → 92.99%(未覆蓋 745 → 69 行、402 → 30 分支);★★ 全 backend:行 91.94%/分支 76.18%。★ 9 類別/83 測(兩模組 201 測/0 失敗)。★★★ 真機反駁我方 6 項(★ 最值得記:MDC_KEY 實為 trace_id;錯誤碼 → HTTP 狀態由登錄表決定,不憑語感(CC-PLT-5002 → 500);Keycloak realm 角色在巢狀 realm_access.roles;截斷在工廠方法非建構子)。★ 殘餘 46 行/56 分支逐條記錄(多為「需 Oracle/Bean Validation 實作/私有巢狀/並發路徑」);掃描器全 0 命中
1.6 2026-10-06 ★★★ 批次 20-d 納入(#A-220)——common-security;★★ 併立並執行 CR-042:★★ 行 73.5% → 98.0%、分支 58.5% → 98.3%(+96 行/+70 分支)。★★ platform/ 8 模組:行 94.83%/分支 86.79%(未覆蓋 222 → 126 行、200 → 130 分支);★★ 全 backend:行 91.56%/分支 74.86%。★ 8 類別/86 測(全模組 137 測/0 失敗)。★★★ 揭露並修補真缺陷(CR-042):JwtAuthFilter.sendUnauthorized() 必拋 NPE(★ Map.of 不接受 null 值)→ ★★ 該過濾器「未認證 → 401」從未真正執行過;★ 查證全庫零接線(不影響現行系統)→ ★ 改用 LinkedHashMap 修補。★★★ 真機反駁我方 1 項(★ #A-163 同型陷阱再次踩到:竄改 Base64 末字元低位被丟棄 → 認證反而通過)。★ 全 backend 編譯驗證通過;掃描器全 0 命中
1.5 2026-10-06 ★★ 批次 20-c 納入(#A-219)——api-gateway:★★ 行 40.7% → 98.9%、分支 50.0% → 95.2%(+163 行/+57 分支)。★★ platform/ 8 模組:行 90.88%/分支 79.67%(未覆蓋 385 → 222 行、257 → 200 分支);★★ 全 backend:行 90.91%/分支 73.35%。★ 6 類別/51 測(全模組 79 測/0 失敗);掃描器全 0 命中。★★ 配方:MockServerWebExchange + GatewayFilterChain lambda + @TempDir + InMemoryRouteDefinitionRepository(真件)+ ContextRefresher 最小子類。★★★ 真機反駁我方 4 項(★ 最值得記:name != null 為死碼——Reactor 禁止 map 回 null;WebFlux 解析 ReactiveJwtDecoder 非 JwtDecoder)
1.4 2026-10-06 ★★★ 批次 20(WBS 5.37)納入——★★★「全 backend」口徑之兩項門檻首次雙雙達標(#A-217/#A-218)。★★★ 全 backend:行 87.42% → 89.82%、分支 68.98% → 72.12%(分支超出 90 條)。★ platform/ 8 模組:行 69.4% → 84.18%、分支 59.1% → 73.88%(未覆蓋 745 → 385 行、402 → 257 分支)。★ 20-a:common-domain/common-batch/common-event 三模組行與分支皆 100%(+56 行/+31 分支)。★★★ 20-b:bff-web 行 30.1% → 97.3%、分支 13.2% → 97.1%(+304 行/+114 分支)。★★ 併更正 §7.2/§7.3/§7.4(原記「分支未達標」與兩個低覆蓋服務皆已過期);★ §7.4 重算:服務側未覆蓋 2,153 → 1,138 行(分層:application 508/infrastructure 431/domain 177/interfaces 22)。★ 掃描器全 0 命中
1.3 2026-10-06 ★★★ 新增「口徑聲明」(#A-216)——★ 本報告之數字為 backend/services/*(17 服務) 口徑;★★ 另有「全 backend」口徑(含 8 個 platform/ 模組)= 行 87.4%/分支 69.0%(★ 分支未達 70%)。★ 兩者皆正確、僅範圍不同;★ platform/ 為 行 69.4%/分支 59.1%(未覆蓋 745 行/402 分支)。★★ 勿誤讀為「全 backend 已達標」
1.2 2026-10-06 ★★★ 補記至批次 17-d(#A-213)之最終狀態:★★★ 行覆蓋 90.92%(11,397/12,535;超出 1,369 行);★★★ 分支覆蓋 71.64%(門檻 70%)——★ 兩項目標皆已達成;1,478 測/0 失敗/1 略過。★ 本報告僅保留至批次 13 之逐批細節(v1.1);★ 批次 14~17-d 見 TRP-003 §6.11.21~§6.11.30。★ 新增批次:14 messaging/15 client(樁伺服器)/16 storage(★ Garage 非 MinIO)/17-a~17-d application(party+rewards+limit+payment,★ WBS 5.36 結案)
1.1 2026-10-06 ★★ 批次 13 納入(#A-205)——outbox 橫向複製至其餘 10 服務。★★ 行覆蓋 80.18% → 82.42%(10,331/12,535;超出門檻 303 行);★ 分支 63.78% → 64.33%(仍未達);測試 1,287 → 1,347。★ 逐服務表、批次總表、殘留缺口(2,433 → 2,153 行)同步更新。★ outbox 套件已全數完成(12/12 服務 100%)
1.0 2026-10-06 ★★ 初版——TRP-003 計畫(B1~批次 12)之總結。★ 行覆蓋 53.7% → 80.18%(目標達成);⚠️ 分支覆蓋 63.78%(未達 70%);1,287 測/0 失敗/1 略過;掃描器全 0 命中。★ 併載真機反駁 13 次之彙總與殘留缺口全貌(2,433 行)。
(46-46/67)