具代表性的面試主題

後端面試:如何用消費者驅動契約測試安全發布微服務 API?

後端困難
Offer.cc 編輯團隊發佈 更新

題幹

一個 API Provider 被多個 Web、行動端和非同步消費者呼叫。請設計消費者驅動契約測試流程,說明契約範圍、狀態隔離、版本選擇、CI 發布閘門與失敗回滾。

題幹與適用場景

一個訂單 Provider 被 Web、行動端與非同步訊息消費者使用。團隊希望在 Provider 發布前發現破壞性變更,但不想每次提交都啟動所有真實服務。請用消費者驅動契約測試設計流程,說明消費者契約寫什麼、Provider 如何驗證、共享 Broker 如何選版本、如何處理 Provider state,以及何時允許部署。

這題考察 API 邊界、測試分層、版本相容與持續交付。Pact 將契約建模為消費者需要的請求和最小回應,並在 Provider 端重播驗證;它不取代單元、整合或端到端測試。

面試官在考察什麼

  • 能否把消費者行為轉成最小互動契約,而不是複製 Provider 全部實作。
  • 能否解釋 mock consumer test、provider verification、Broker 和部署矩陣的完整資料流。
  • 能否用 Provider state 隔離前置資料,避免測試依賴共享資料庫或隨機真實資料。
  • 能否處理多版本消費者、未驗證契約、訊息契約和失敗回滾。

先釐清哪些問題

  1. 是 HTTP、非同步訊息,還是兩者都有?訊息契約和 HTTP 互動的載體不同。
  2. 哪些欄位是真正被消費者使用的?契約應只表達必要請求和最小回應。
  3. Provider state 能否在測試環境建立、清理和參數化?依賴是否需要 stub?
  4. 版本如何標識,生產部署前需要滿足哪些消費者/Provider 組合?
  5. 是否有 Broker、分支標籤、pending pact 和回滾策略?

30 秒回答框架

消費者先用 mock 寫互動測試,產生只含必要請求和回應斷言的 Pact;契約發布到 Broker。Provider 驗證器取回目標消費者版本,準備 Provider state,在本機或隔離環境重播請求並發布驗證結果。CI 的部署閘門查詢目前版本組合是否已驗證,未驗證的新契約先進入 pending 或阻止發布。契約只保證訊息形狀和互動,不承擔全部業務正確性;失敗時停止部署、修復 Provider 或回滾到仍被驗證的版本。

分步作答

1. 從消費者行為定義互動

每個互動描述請求方法、路徑、必要標頭、關鍵請求欄位和最小回應斷言。消費者測試呼叫 Pact mock,而非 Provider 真實實例;這樣能快速產生可分享契約檔案,並讓斷言跟隨消費者實際使用。

text
consumer test -> pact file -> broker
provider verifier + provider state -> replay -> verification result
deployment gate -> compatible version matrix -> deploy or block

2. 讓契約保持最小且穩定

不要斷言未使用的回應欄位、隨機 ID 或完整資料庫快照。使用 matching 表達型別、格式和必要結構;時間、UUID 等動態值只驗證形狀。契約測試關注通訊訊息,不應變成 Provider 的通用功能測試。

3. 設計 Provider state

Provider state 是每個互動的前置條件,例如「訂單已付款」。驗證前透過 state handler 建立或 stub 資料,驗證後清理。狀態參數必須可追蹤、冪等且不洩露生產憑證;不要讓多個互動共享不可控順序。

4. 用 Broker 管理版本和驗證

消費者發布契約並帶上分支、版本或環境標籤;Provider 驗證目標消費者版本並回寫結果。部署閘門檢查候選 Provider 版本與即將部署的消費者版本組合,而不是只看「最新契約是否綠」。對新出現但尚未驗證的契約,可使用 pending 行為先驗證並記錄,再決定是否阻斷。

5. 選擇發布順序與相容窗口

相容變更通常先部署能相容舊請求和舊回應的新 Provider,再升級消費者;破壞性變更需要雙讀/雙寫、版本化路徑或遷移窗口。非同步訊息使用 message pact 驗證訊息端口,仍需測試真實 broker 的投遞、重試和順序語意。

6. 失敗處置與觀測

記錄契約失敗的互動、Provider state、版本、提交 SHA 和環境。失敗時阻止部署並回滾到最後一個通過部署矩陣的版本;上線後繼續觀察 4xx/5xx、反序列化錯誤、訊息死信和業務指標。測試綠不代表生產一定正確,必須保留執行期保護。

高品質示範答案

我會讓每個消費者用 Pact mock 編寫真實互動,產生只含必要請求和最小回應的契約並發布到 Broker。Provider 驗證器按消費者版本選擇契約,在隔離環境執行可重複的 Provider state,重播請求並把結果、Provider 版本和提交 SHA 回寫。CI 部署閘門查詢即將組合的消費者/Provider 版本是否都有驗證記錄;pending pact 可讓新契約先被驗證而不立即破壞舊 Provider。

契約只覆蓋通訊形狀和使用欄位,不能取代單元、整合、端到端及業務測試。相容演進先保證 Provider 讀舊請求、回傳舊消費者能理解的回應,再升級消費者;破壞性變化使用版本化路徑或雙寫窗口。失敗時阻斷發布並回到最後通過矩陣的版本,同時保留執行期錯誤、死信和業務指標觀測。非同步場景用 message pact 驗證訊息內容,但另行驗證 broker 語意。

常見失分點

  • 把契約寫成 Provider 全量回應快照,導致無關欄位變化頻繁阻斷。
  • 只執行消費者 mock,不在 Provider 實例上重播驗證。
  • Provider state 依賴共享資料庫順序、隨機資料或生產憑證。
  • 只比較最新版本,不檢查實際部署組合和長尾消費者。
  • 把 Pact 當成端到端測試,忽略真實 broker、權限、效能和業務規則。
  • 驗證失敗仍繼續部署,或沒有可驗證的回滾版本。

追問與參考回答

為什麼契約回應要最小化?

消費者只應鎖定真正依賴的欄位。最小回應減少偶然耦合,讓 Provider 可以新增不影響消費者的欄位。

Provider state 和測試 fixture 有什麼差別?

Provider state 是互動前置條件的可執行介面,可由驗證器在 Provider 環境設定和清理;fixture 只是測試資料載體,未必能跨服務建立正確狀態。

pending pact 解決什麼問題?

它允許新契約先進入 Broker 並執行驗證,在首次出現且尚未被 Provider 證明時不立即讓舊 Provider 建置失敗;是否啟用要結合組織發布策略。

如何避免契約數量失控?

按真實消費者互動去重,刪除已退役版本,限制隨機欄位和全量快照,並讓 Broker 記錄 owner、版本和最後驗證時間。

消費者版本選擇為什麼重要?

部署閘門要驗證實際即將協同運行的版本組合;只驗證 main 或 latest 可能漏掉生產中的舊行動端或分支版本。

Pact 能證明 Provider 的業務正確嗎?

不能。它證明互動滿足消費者契約;業務不變量、效能、授權、故障恢復和真實基礎設施仍需其他測試與生產觀測。

公開來源

同類題目