核心理念#
有了部署管線的基礎後,下一步是建立快速且可靠的自動化測試,在整個軟體開發生命週期中持續驗證我們的程式碼處於可部署狀態。自動化測試的目標是讓開發者能在安全的環境中快速獲得回饋,確保變更不會破壞現有功能。
持續建構、測試與整合#
我們的目標是在部署管線的每個階段建構自動化測試,以便儘早發現問題。傳統上,測試只在開發結束後才進行——由獨立的 QA 團隊在類生產環境中手動執行。這種做法有嚴重的問題:
- 發現缺陷時,距離引入缺陷的變更已過了很長時間
- 修復成本高,回饋循環慢
- 測試結果不可靠,無法重現
我們需要在開發者提交程式碼時就執行自動化測試,而不是等到專案末期。這是從「事後檢查品質」轉變為「在流程中建構品質」的關鍵。
自動化測試的層次#
單元測試(Unit Tests)#
- 測試單個方法或函式的行為
- 執行速度最快(通常毫秒級)
- 不依賴資料庫、檔案系統或其他外部服務
- 應佔測試套件的大部分比例
驗收測試(Acceptance Tests)#
- 測試應用程式作為一個整體是否按預期運作
- 驗證業務需求和使用者故事的正確性
- 通常在類生產環境中執行
- 可能需要較長的執行時間
整合測試(Integration Tests)#
- 確保我們的應用程式能與其他應用程式和服務正確互動
- 在類生產環境中測試系統之間的交互
- 通常是最慢且最脆弱的測試
測試金字塔#
Mike Cohn 在《Succeeding with Agile》中提出的測試金字塔概念指導我們如何分配測試比例:
- 底部(最多):單元測試——快速、便宜、覆蓋面廣
- 中間:整合測試和 API 測試
- 頂部(最少):UI 測試和端到端測試——慢速、昂貴、脆弱
理想的測試組合是大量的單元測試提供快速回饋,配合較少但關鍵的驗收測試和整合測試確保系統整體行為正確。
儘早在管線中發現錯誤#
自動化測試最重要的原則是越早發現問題越好。在部署管線中,測試應按照執行速度排列:
- 提交階段:執行單元測試和程式碼分析(秒到分鐘)
- 驗收階段:執行自動化驗收測試(分鐘)
- 整合階段:執行整合測試(分鐘到小時)
- 手動驗證階段:探索性測試(依需要)
當任何階段的測試失敗時,管線應該立即停止,整個團隊需要修復問題後才能繼續。
確保測試可靠#
不可靠的測試(flaky tests)是自動化測試的最大敵人。當測試結果不一致時:
- 開發者開始忽略測試失敗
- 團隊失去對測試套件的信任
- 最終導致沒有人關注測試結果
處理不可靠測試的策略:
- 隔離:將不可靠的測試移到單獨的測試套件
- 修復或移除:限期修復,無法修復就刪除
- 監控:追蹤測試的穩定性指標

Figure 12: Functional vs. market orientation
使測試快速執行#
測試套件的執行速度直接影響回饋循環的長度。當測試需要數小時才能完成時,開發者無法獲得及時回饋。加速測試的方法包括:
- 並行執行:在多台機器上同時執行測試
- 測試分片:將測試套件分成多個片段並行執行
- 最佳化測試設計:減少不必要的測試前置準備和清理
- 使用 test doubles:用 mock、stub 替代慢速的外部依賴
Google 對測試速度有嚴格的要求:「小型」測試必須在 60 秒內完成,「中型」測試在 300 秒內,「大型」測試在 900 秒內。超時的測試會被自動標記和處理。
將自動化測試整合到開發者日常工作#
自動化測試不應該是一個獨立的活動,而應該成為開發流程的一部分:
- 開發者在提交前就在自己的工作站上執行測試
- 每次提交都自動觸發測試管線
- 測試失敗的修復優先於新功能開發
- 停止生產線(stop the line):當建構失敗時,整個團隊的首要任務是修復它
測試驅動開發(TDD)#
測試驅動開發是一種強大的開發實踐,遵循「紅-綠-重構」循環:
- 紅:先寫一個會失敗的測試
- 綠:寫最少的程式碼讓測試通過
- 重構:在保持測試通過的前提下改善程式碼結構
TDD 的好處包括:
- 確保每段程式碼都有對應的測試覆蓋
- 引導更好的設計決策
- 提供即時的回饋循環
- 產生可作為文件的測試套件
自動化測試作為安全網#
完善的自動化測試套件就像一張安全網,讓團隊能夠:
- 自信地重構:知道測試會捕捉到意外的行為變更
- 快速部署:自動驗證取代了冗長的手動測試週期
- 減少恐懼:降低「害怕改動程式碼」的心理障礙
- 知識保存:測試記錄了系統預期的行為
結論#
快速且可靠的自動化測試是持續交付的基石。透過在部署管線的每個階段建構適當的測試,我們能在問題引入時立即發現並修復,而不是等到部署到生產環境後才發現。這不僅提高了軟體品質,也讓開發者更有信心進行變更和創新。