Project

General

Profile

CR #201 » CSP-005_單元測試與品質規範.md

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

 

CSP-005 單元測試與品質規範(Unit Test & Quality)

項目 內容
文件編號 CSP-005
版本 1.0
狀態 已核定
撰寫者 SA / QA Lead
審查者 PMO / TestBOT
對應需求 NFR-QUAL 品質群組;BRD-004 POC 驗收情境

1. 目的

定義單元測試的撰寫標準、覆蓋門檻、品質閘與禁止事項,確保交付程式碼具備可驗證的正確性。
本規範與 TRP-001(測試計畫)互補:TRP-001 管「驗收測試劇本」,本規範管「開發期單元測試」。


2. 測試金字塔

flowchart TD
    U[Unit 單元測試 ~70%] --> I[Integration 整合 ~20%]
    I --> E[End-to-End / POC 驗收 ~10%]
    style U fill:#EEF3F8,stroke:#0B2E59
    style E fill:#FFF6E0,stroke:#C8A45C
  • 單元測試:不啟動 Spring 容器、不連 DB;以純邏輯測 domain/ 與 application/ handler。
  • 整合測試:以 Testcontainers 起 PostgreSQL / Kafka,驗證 infrastructure/ 真實接線。
  • E2E / POC:對應 BRD-004 的 17 項情境,經 api-gateway 端到端跑。

3. 單元測試撰寫約定

  1. 框架:JUnit 5(@Test)、AssertJ(斷言)、Mockito(僅用於隔離外部依賴,不得 mock 被測邏輯本身)。
  2. 命名:<受測方法>_<情境>_<預期>。例:approve_whenLimitSufficient_returnsApproved()。
  3. 結構:遵守 Given-When-Then;每個測試只驗證一個行為。
  4. 資料:測試內的 given 資料合法(真實格式的卡號、金額),不得用 null 或無意義假值掩飾。
  5. 邊界:每個業務規則至少 3 例(正常值、下界、上界/例外)。

4. 覆蓋率與品質閘(CI 強制)

指標 門檻 工具
行覆蓋率(line) ≥ 80% JaCoCo
分支覆蓋率(branch) ≥ 70% JaCoCo
Mutation 存活率 ≤ 25%(即殺死率 ≥ 75%) PITest
靜態分析 0 error Checkstyle / SpotBugs / PMD
禁止模式掃描 0 命中 scan_scaffold / scan_mockdata

門檻為合併前紅線:任一未達標,CI 失敗、PR 不得合併。

4.1 量測方式(2026-10-02 補;#A-160)

項目 內容
工具接線 backend/build.gradle.kts 之 subprojects {} 內 apply(plugin = "jacoco")(由 tools/gen_service_skeleton.py 之 T_ROOT_BUILD 產生——改動須兩邊都動)
產出 每個模組 build/reports/jacoco/test/html/(人看)+ build/reports/jacoco/test/jacocoTestReport.xml(供 tools/verify_nfr.py 解析)
執行 cd backend && ./gradlew test jacocoTestReport
門檻任務 jacocoTestCoverageVerification 已定義(行 0.80/分支 0.70);⚠️ 尚未接入 check——待基線補足後開啟(見 TRP-002 §7.2)
Mutation PITest(≥75%)尚未接入——PIT 執行成本高,另立任務

4.1.1 ★ 排除規則(刻意從嚴)

僅排除「機器產生」與「純啟動類」兩類,其餘一律計入:

排除樣式 理由
**/ErrorCodes.class 由 tools/gen_error_codes.py 產生(依 SDD-006 §3.4)——非人手撰寫
**/*Application.class Spring Boot 啟動類(無業務邏輯)

⚠️ 刻意不排除 DTO/View/Request/Config——業界慣例常排除之,但那會虛胖覆蓋率。
本專案之 record 雖多為資料載體,仍可能有驗證與正規化邏輯(例:SpecialLimit#coversMcc)。
寧可數字難看,不要數字騙人(GOV-007 反假綠)。
如日後確有排除需求,須逐類具名並於本節載明理由,不得以「**/dto/**」通吃。

⚠️ 未接入 check 之門檻=目前不會擋 PR——此為已知之過渡狀態,
目的在「先量到真實基線」再設門檻;TRP-002 §7.2 #1 已列此缺口。

4.2 ★★ 實測基線(2026-10-02,#A-160)

指標 實測 門檻 判定
行覆蓋率 53.7%(8,034/14,970) ≥ 80% ❌ 未達
分支覆蓋率 46.8%(2,164/4,623) ≥ 70% ❌ 未達

★★ 此數字不是計法造成的假象:已做對照——若改採業界慣例(排除
*View/*Request/*Response/*Dto/*Config/*Properties 等),結果為 行 53.8%/分支 46.7%,
與本節計法幾乎相同(差 0.1 pp)。→ 低覆蓋率源自「真實邏輯缺測試」。
逐模組數據、最低三者與後續建議見 docs/08-evidence/N1_工具缺口補齊與量測結果.md §1。

4.3 依賴漏洞掃描(#A-160 新增)

項目 內容
後端工具 tools/scan_deps.py(OSV;零相依;以 Gradle init script 列舉 runtimeClasspath,不改 repo)
前端工具 npm audit
判定 有 High/Critical 或嚴重度未知 → 退出碼 1(fail-closed)
實測 後端 3 CRITICAL+10 HIGH(Tomcat 11.0.24/Jackson 2.21.5·3.1.5);前端 1 HIGH+3 MODERATE
修補(CR-037,2026-10-05) ✅ Tomcat 11.0.24 → 11.0.26(3 個 CRITICAL 歸零)
修補(CR-038,2026-10-05) ✅ Jackson 2.21.5 → 2.21.7/3.1.5 → 3.1.7(10 個 HIGH 歸零)
修補(CR-040,2026-10-05) ✅ 前端 vite 5.4.21 → 8.3.2/react-router-dom 6.30.6 → 7.18.4/@vitejs/plugin-react 4.3.4 → 6.1.1(HIGH 1 → 0;MODERATE 3 → 0)
現況 後端 CRITICAL 0/HIGH 0/MODERATE 0(CR-037/CR-038/CR-039)+ 前端 0(CR-040)→ ★★ npm audit 與 OSV 掃描皆 0 命中
對準出之影響 TRP-001 §6.2 第 7 條「安全掃描無高/嚴重漏洞」→ ★ 後端與前端皆達成(⚠️ 滲透測試仍屬外部環境,見 TRP-002 §5)

⚠️ 升版前須做版本相容性查證(CSP-006 之版本為單一真實來源)——不得直接改版號。


5. 測試資料策略

  • 不依賴共享資料庫狀態:每個測試自給自足(arrange 自己建資料),以 @BeforeEach 重置或使用
    獨立 schema。
  • 整合測試用 Testcontainers 起一次性容器,測完即銷毀;禁止連「開發/測試共享真庫」跑單元測試。
  • 個資:測試資料一律使用合成卡號(如 4000********1234 之測試卡 bin),禁止真實客戶資料。

6. 禁止事項(客戶硬性要求:不得有「假測試」)

編號 禁止 說明
T1 假斷言:assertTrue(true)、assertEquals(1,1) 之類無效驗證 偽裝通過,毫無意義
T2 吞失敗:@Test 內 try{...}catch{ /*ignore*/ } 隱藏錯誤
T3 mock 取代真實邏輯:when(service.calc()).thenReturn(42) 然後只驗證 42 被回傳,卻沒測 calc() 本身 應直接對 calc() 做單元測試
T4 @Disabled 長期停用而不開 issue 追蹤 測試債務累積
T5 塞框架:測試類只有 setUp 無任何 @Test 空殼(對應 CSP-001 B1)
T6 依賴執行順序:測試間有隱含次序才過 不可重現

掃描器:cardcore/tools/scan_faketest.py 於 CI 偵測 T1/T3/T5 模式(如 assertTrue(true)、
verifyNoInteractions 卻無 when、類別無 @Test 方法),命中即紅燈。


7. 與 POC 驗收之連結

BRD-004 之 17 項 POC 情境,每一項對應至少一組 E2E 測試(命名 Poc<NN>_*.test),
其通過狀態直接回寫 GOV-004 追溯矩陣。未通過之 POC 測試,標記 BLOCKED 並開缺陷單(TRP-001 §5)。


8. 交付前自檢清單(Coder 提交 PR 前)

  • 單元測試通過、覆蓋率達標
  • 無 T1–T6 禁止模式
  • 靜態分析 0 error
  • 無 TODO/FIXME(CSP-001 B5)
  • 提交訊息含 Refs: FR/NFR-XXX
  • 新增 API 已同步 contracts/openapi/*.yaml
(34-34/67)