微服務下的契約測試(CDC)解讀


1. 前言

        有近兩周沒有在公眾號中發表文章了,看過我之前公眾號的讀者都知道,公眾號中近期在連載《RobotFramework接口自動化系列課程》,原本計划每周更新一篇,最近由於博主在帶一個新項目,實在是沒空抽出時間來,所以向公眾號中對連載課程一直期待的讀者說聲抱歉。

      由於最近帶微服務的項目,而對於微服務其實也是近從14年才流行起來,對於這塊目前網上的干貨內容還是較少,借着機會,小結一下知識點。所以今天也先不打算連載《RobotFramework接口自動化系列課程》,如果讀者對連載的課程比較熱衷的話,可以在留言板下面給筆者留言,如果讀者反饋較多的話,博主也會適當加快調整課程分享節奏。

 

下面就給大家淺聊一下微服務架構下的契約測試。

 

2.  微服務特點

Microservice微服務是一種架構風格,我們可以把每一個微服務視做一個用一組API提供業務功能的組件,且服務之間會有很多依賴關系,如下圖所示: 


這些服務之間可能由一個團隊或者相互獨立的團隊開發和維護,並且它們在系統內部相互依賴,在這種情況下,接口的開發和維護可能會帶來一些問題,例如服務端調整架構或接口調整而對消費者不透明,導致接口調用失敗。

 

注:關於微服務的基本組件組成及介紹,后面考慮單獨抽離一篇文章進行介紹,本文就不過多說了~

 

 

3. 微服務下的測試現狀

  

例如, 我們想測試某微服務架構中的某一個服務時,比如下圖第一排中間的服務,如: 

因為它和其他服務都存在交互,一般我們有兩種方式:

  • 部署所有的服務來實現端到端測試。

  • 在集成測試中Mock其他服務。

 

下面分析一下這兩種方式優缺點:

對比分析 優點 缺點
第一種方式:部署所有服務 1、模擬生成環境
2、可以真實地測試服務交互
1、測試其中一個服務,不是不布署全部服務,包括各基礎設施
2、要運行很長時間
3、不能及時給予測試反饋
4、測試環境被一個測試服務鎖定,別人無法同時使用。
第二種方式:Mock其它服務 1、測試反饋快
2、沒有基礎服務依賴要求
1、服務的實現方創建的Stubs,可能實現與這個無關
2、無法模擬真實數據交互環境

 

 

4、微服務下的開發現狀

 

常規我們開發的項目主要由服務提供方約定接口,雖然提供方架構調整或改變接口之前通常會通知消費者,但可能還是會存在遺漏。

當一個Service已經同時被多個使用者調用用的時候,怎么保證service的修改對其它所有使用者造成影響都被感知到呢?

 

那么契約測試的引出就是為了解決這類問題的最佳方案!

 

5、什么是契約測試(CDC)

     契約測試 ,又稱之為 消費者驅動的契約測試(Consumer-Driven Contracts,簡稱CDC),根據 消費者驅動契約 ,我們可以將服務分為消費者端和生產者端,而消費者驅動的契約測試的核心思想在於是從消費者業務實現的角度出發,由消費者自己會定義需要的數據格式以及交互細節,並驅動生成一份契約文件。然后生產者根據契約文件來實現自己的邏輯,並在持續集成環境中持續驗證。

后文中消費者驅動的契約測試統一用cdc來代替。

cdc核心原則:

  • cdc是以消費者提出接口契約,交由服務提供方實現,並以測試用例對契約進行產生約束,所以服務提供方在滿足測試用例的情況下可以自行更改接口或架構實現而不影響消費者。

  • cdc是一種針對外部服務的接口進行的測試,它能夠驗證服務是否滿足消費方期待的契約。 它的本質是從利益相關者的目標和動機出發,最大限度地滿足需求方的業務價值實現。

 

 

6、契約測試、單元測試、接口測試區別

  

  • API測試和單元測試,更強調的是覆蓋API內部邏輯。

  • 契約測試,更強調是組件之間連接的正確性,除了保證組件內部,還要保證組件間的調用是正確的,也就是服務API之間的調用。

單元測試 單元測試針對代碼單元(通常是類)的測試,單元測試的價值在於能提供最快的反饋。另外好的單元測試還可以幫助你改善設計,在你的團隊掌握TDD的前提下,單元測試能輔助重構,幫助改善代碼整潔度。
API測試 API測試是針對業務接口進行的測試,主要測內部接口功能實現是否完整,比如說內部邏輯是不是正常,異常處理是不是正確。
契約測試 契約測試其實是為了測試服務之間連接或者說接口調用的正確性,為了驗證服務提供者的功能是不是真正能夠滿足消費者的需求。它其實體現了測試前移的思想,把本來要通過集成測試才能驗證的工作化作單元測試和接口測試,用更輕量的方式快速進行驗證。
集成測試 它從用戶的角度驗證整個功能的正確性,測的是端到端的流程,並且加入用戶場景和數據,驗證整個過程是不是OK,它的價值業務價值最高,是驗證一個完整的流程。

 

 

7、契約測試能解決什么問題?

  • 聯調成本過高,要雙方開發到某一階段后放在同一個環境上才能進行,要同時把握雙方的進度,造成資源和時間上的浪費。

  • 對於接口的變動把控相當困難。由於接口變動是普遍存在的,尤其對於調用關系復雜的接口,一旦發生變動,如果沒有一套機制進行控制,驗證的成本巨大。 

  • 接口不匹配”是指服務依賴於彼此間的接口進行通信,如何保證改變一個服務的接口會對其他所有依賴服務是否造成造成影響。 

  • 在發生契約變化時,提供一種可立即被服務端和消費端發現的方式。

 

 

8、契約測試能給我們帶來什么?

 

  • 降低服務集成的難度,把服務集成這個過程分解成了單元測試和接口測試來做,它從消費者的需求為出發點,把消費者的需求作為你的測試用例驅動出一份契約,然后驗證提供者端的功能。

  • 通過使用契約測試,接口調用雙方協商接口后就可以並行開發,並且在開發過程中就利用契約進行預集成測試,不用等到聯調再來集成調通接口,一旦成熟,在保證質量的前提下,聯調的成本可以減低到幾乎為0。

  • 因為契約的存在,讓接口的變動有跡可循,即使變動也可以確保變動的安全性和准確性。 

  • 通過契約測試,團隊能以一種離線的方式(不需要消費者、提供者同時在線),通過契約作為中間的標准,驗證提供者提供的內容是否滿足消費者的期望。

 

 

9、契約測試之Pact工具

 

9.1 Pact 術語介紹

  • Consumer: 微服務接口的調用者

  • Provider: 微服務接口的提供者

  • 契約文件: 是由consumer端和provider端共同定義的接口規范,包括接口訪問的路徑,輸入和輸出數據。在具體的實施中,是由consumer端生成的一個json文件,並存放在pact broker上

  • Pact Broker: 保存契約文件的服務器

    注:通常在工程實踐上,當消費者根據需要生成了契約之后,我們會將契約上傳至一個公共可訪問的地址,然后生產者在執行時會訪問這個地址,並獲得最新版本的契約,然后對着這些契約來執行相應的驗證過程。

     

9.2 Pact 基本流程 

簡要流程:

  • 第一步在消費者端Consumer端寫一個對接口發送請求的單元測試,在運行這個單元測試的時候,Pact會將服務提供者自動用一個MockService代替,並自動生成契約文件,這個契約文件是Json形式的。

     

  • 第二步在Provider端做契約驗證測試,將Provider服務啟動起來以后,通過pact插件可以運行一個命令,比如你是用maven,就是mvn pact:verify,它會自動按照契約生成接口請求並驗證接口響應是否滿足契約中的預期,所以可以看到這個過程中,在消費者端不用啟動Provider,在服務提供端不用啟動Consumer,卻完成了與集成測試類似的驗證。

 

詳細流程:

基於消費者的業務邏輯,驅動出契約 

  其實現步驟如下所示: 
  1、使用Pact的DSL,定義Mock提供者,如localhost:8080 
  2、將Mock地址傳給消費者並對Mock的提供者發送請求。 
  3、使用Pact的DSL,定義響應內容(包括Headers、Status以及Body等)。 
  4、在消費者端 使用@PactVerification運行單元測試(Pact集成了JUnit、RSpec等框架),生成契約文件。 
  5、當運行測試后,Pact框架記錄消費者的名稱、發送的請求、期望的響應以及元數據,將其保存為當前場景下的契約文件,通常命名為[Consumer]-[Provider].json,例如 orderConsumer-orderProvider.json 
  6、契約文件生成后,我們可以將其保存在文件系統或者Pact-Broker(Pact提供的中間件,用來管理契約文件)中,以便后續提供者使用。

基於消費者驅動出的契約,對提供者進行驗證 

  在提供者端,我們不需要寫任何驗證的相關代碼,Pact已經提供了驗證的接口,我們只需要做好如下配置: 

1、為提供者指定契約文件的存儲源(如文件系統或者Pact-Broker)。 
2、啟動提供者,運行PactVerify(Pact有Maven、Gradle或者Rake插件,提供pactVerify命令)。 
3、當執行pactVerify時,Pact將按照如下步驟,自動完成對提供者的驗證: 
構建Mock的消費者。 
4、根據契約文件記錄的請求內容,向提供者發送請求。 
5、從提供者獲取響應結果。 
6、驗證提供者的響應結果與Pact契約文件定義的契約中是否一致。

 

9.3 Pact 特性

傳統情況下做集成測試需要把服務消費者和服務提供者兩個服務都啟動起來再進行測試,而Pact做契約測試時將它分成兩步來做,每一步里面都不需要同時啟動兩個服務。

1、測試解耦,就是服務消費與提供者解耦,甚至可以在沒有提供者實現的情況下開始消費者的測試。 
2、一致性,通過測試保證契約與現實是一致性的。 
3、測試前移,可以在開發階段運行,並作為CI的一部分,甚至在開發本地就可以去做,而且可以看到一條命令就可以完成,便於盡早發現問題,降低解決問題的成本。

4、Pact提供的Pact Broker 可以自動生成一個服務調用關系圖,為團隊提供了全局的服務依賴關系圖。

5、Pact提供Pact Broker這個工具來完成契約文件管理,使用Pact Broker后,契約上傳與驗證都可以通過命令完成,且契約文件可以制定版本。

6、使用Pact這類框架,能有效幫助團隊降低服務間的集成測試成本,盡早驗證當提供者接口被修改時,是否破壞了消費者的期望。 
7、Pact目前僅支持REST HTTP 通信,但對於RPC的通信機制,暫不支持。

 

 

注:寫到最后,夜也深了,如果你覺得本文對你有點啟發或者作用,歡迎打賞支持一下~

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM