混合測試策略:根據架構層級選擇測試方法
開始實踐 TDD 時,我們遇到一個困惑的問題:什麼都測,還是只測部分?
追求覆蓋率,會寫出大量測試 getter 和直接欄位映射的測試,維護成本高,保護力低。不管覆蓋率,又很難有信心說業務邏輯正確。
答案是:測試策略跟著架構走。
問題的根源
全面單元測試的問題是,重構 ViewModel 內部實作時,大量測試跟著壞掉,但行為根本沒變。全面 BDD 的問題是,Domain 層邊界條件很難透過業務語言的場景完整覆蓋。
不同層級的程式碼,用不同的測試方法。
五層架構的測試分工
Layer 1(UI/Presentation) 只針對關鍵互動流程撰寫整合測試。判斷標準:流程失敗是否影響核心業務、是否需要多步驟操作、是否涉及金流或敏感資料。靜態展示頁面、簡單列表交給人工測試。
Layer 2(Application/Behavior) 只針對複雜轉換邏輯撰寫單元測試。判斷標準:轉換是否包含條件判斷、計算邏輯、多個來源資料,或邏輯超過十行。簡單的 DTO 欄位直接映射,不需要獨立測試,由 UseCase 層間接覆蓋。
Layer 3(UseCase) 所有業務場景都必須撰寫 BDD 測試,沒有例外。每個 UseCase 至少涵蓋一個正常流程、兩個異常流程、三個邊界條件。格式使用 Given-When-Then,只 Mock 外層依賴,使用真實的 Domain Entity。
Layer 4(Interface) 不測試。介面只定義合約,沒有可測試的行為。
Layer 5(Domain Implementation) 複雜業務規則必須撰寫單元測試。判斷標準:是否包含業務規則驗證、計算邏輯、狀態轉換、不變量檢查。Email 格式驗證、金額範圍、訂單狀態轉換都需要完整的單元測試。純資料容器的 Entity 不需要獨立測試。
做決策的流程
確定程式碼屬於哪一層(目錄結構直接反映架構層級),然後問一個問題:
- UI 層:這是關鍵互動流程嗎?
- Behavior 層:這裡有複雜轉換邏輯嗎?
- UseCase 層:直接寫 BDD 測試。
- Interface 層:不測試。
- Domain 層:這裡有複雜業務規則嗎?
答案是就寫,不是就跳過讓上層覆蓋。
技術性測試項目
不分層級都要納入:
- Null 值和空集合
- 邊界值(零、負數、最大值)
- 異常處理(網路錯誤、儲存失敗)
- 資料驗證(格式、範圍、必填欄位)
這些容易被忽略,但往往是上線後出問題的地方。
覆蓋率的意義
這套策略讓覆蓋率指標更有意義。UseCase 層要求行為場景覆蓋率 100%,是所有業務場景都有測試,不是追求程式碼行數百分比。Domain 層複雜邏輯要求分支覆蓋率 100%,每個分支都代表一個業務決策。整體新增程式碼維持 80% 以上。
數字背後有實際意義,不是為了報告好看。
測試的穩定性
UseCase 層的 BDD 測試關注行為,重構內部邏輯只要業務行為沒變,測試就不需要動。Domain 層只有規則本身改變才需要更新。Behavior 層只測複雜的轉換邏輯,重構簡單映射不影響測試。
測試應該是開發的保護網,不是阻力。測試因為業務改變而失敗,那很好;因為重構而大量失敗,那是設計問題。