做爲構建複雜系統的架構,微服務在開發社區中得到了巨大的吸引力。雖然人們開始明白它並非解決全部應用程序架構問題的靈丹妙藥,可是分享與依賴關係和擴展相關的挑戰的應用程序能夠從中受益不淺。數據庫
微服務的採用率正在上升,但與理解如何測試微服務相關的鬥爭也在增長。來自ThoughtWorks的Toby Clemson 在枚舉您可能想要在微服務架構中使用的測試策略方面作得很是出色(請參閱他的文章,瞭解您可能想要建立的不一樣類型的測試),但主流知識如何構建和維護這些不一樣類型的測試仍處於起步階段。編程
可是,在許多方面,測試微服務應用程序與測試使用任何其餘架構構建的應用程序沒有什麼不一樣。微服務使用衆所周知的技術,例如REST或隊列,軟件行業已經擁有完善的測試工具和最佳實踐。微服務面臨的獨特挑戰是構成應用程序的服務數量以及服務之間的依賴關係。此外,每一個微服務仍然須要正常運行,即便它們所依賴的其餘微服務不可用或響應不正確。微信
微服務在彼此交互時一般遵循兩種模式:編排和反應(編排)。許多微服務使用組合的「混合」方法。在這篇文章中,我將提供一些策略來解決在爲使用這些不一樣模式的微服務建立自動化測試時出現的一些挑戰,重點關注單個微服務的測試(而不是整個應用程序的端到端測試) )。架構
使用業務流程的微服務將對外部服務或依賴項進行一次或屢次顯式調用。這些調用一般使用同步請求 - 響應流,而且一般會訪問基於REST的服務。若是須要以特定順序調用服務,則在收到對先前服務的調用的響應以前,不會調用後續服務。由於一個服務明確地調用另外一個服務,因此它們緊密耦併發
在上面顯示的示例中,爲Portfolio微服務建立和執行測試具備挑戰性,由於Portfolio微服務依賴於Accounts和Quotes微服務,這些微服務須要與Portfolio微服務一塊兒部署在測試環境中。Quotes服務依賴於第三方服務來檢索實時股票價格,而且該服務返回的數據老是在變化。app
依靠不一樣團隊開發的第三方服務或服務極大地增長了測試環境的複雜性。此外,須要測試Portfolio服務的任何意外行爲,例如當Accounts和/或Quotes服務不可用,響應緩慢或響應意外數據時。可以使這些服務響應不一樣類型的意外行爲以驗證Portfolio微服務是否正確處理錯誤條件很是重要。框架
您可使用服務虛擬化 來模擬賬戶和報價微服務的響應。經過服務虛擬化,您能夠定義賬戶和報價微服務的虛擬版本,並將它們與Portfolio微服務的實際實例一塊兒部署。虛擬化微服務相似於虛擬化任何其餘類型的服務或應用程序架構。它可能看起來像這樣:異步
完成此操做後,能夠獨立於其兩個依賴項測試Portfolio微服務。ide
下一個挑戰是爲不一樣的狀況配置不一樣的環境,例如當Accounts和Quotes服務顯示預期和意外行爲時。假設團隊但願在Accounts服務或Quotes服務響應緩慢或響應錯誤條件時測試Portfolio服務的行爲方式。這可能須要運行至少5組不一樣的測試,每組測試具備不一樣的環境配置,考慮到響應時間慢,錯誤響應以及從屬服務的正常和異常行爲。微服務
對於每次測試運行,在運行該配置的測試以前,須要將環境置於正確的配置中。在這個例子中,咱們最終獲得至少五個不一樣的測試運行,每一個測試運行都有本身的環境配置。Parasoft的Continuous Testing Platform中的Environment Manager模塊能夠爲您管理這些不一樣的環境配置:
此過程並不是特定於微服務架構 - 通常而言,面向服務的體系結構中出現相同類型的問題,以及可能僅依賴於少數服務的單片應用程序。然而,在微服務架構中,依賴服務的數量顯着增長。在具備數十或數百個服務的微服務環境中,爲不一樣的測試場景建立,管理和以編程方式在不一樣環境配置之間切換的能力很是重要,而且能夠顯着減小時間和精力。
隨着團隊不斷髮展他們的微服務,不可避免地會對服務進行API更改。API更改帶來的一個關鍵問題是如何理解這些更改對服務使用者的影響。
當團隊爲他們正在構建的微服務修改API時,任何驗證微服務的測試都須要根據API中的更改進行更新。相反,若是虛擬服務用於模擬依賴的微服務和用於其中一個依賴的微服務更改的API,則必須更新依賴微服務的虛擬服務以反映API中的更改。
許多團隊使用OpenAPI,RAML或其餘服務定義來描述其微服務的API。使用服務定義時,Parasoft SOAtest和Parasoft Virtualize中的Change Advisor模塊 能夠自動檢測哪些API已更改,而後自動重構現有功能測試或虛擬服務,以使用API中的任何新字段和/或已刪除字段更新它們。團隊能夠建立其服務定義的更新版本,並在進行更改以前使用Change Advisor瞭解更改對其測試和虛擬服務的影響。一旦進行了更改,Change Advisor就能夠快速輕鬆地更新現有資產,以反映微服務中的變化。
微服務架構的主要目標之一是建立獨立的組件。所以,部署,擴展和更新服務將變得更加容易。可是,在使用業務流程模式時,並未徹底實現此目標,由於各個微服務對其餘微服務具備直接依賴性。解決此問題的方法是使用編排模式,也稱爲「反應」或「事件驅動」微服務。在這種模式中,微服務不直接相互引用。相反,他們將消息推送到其餘微服務已訂閱的事件流。
請參閱如下示例:
在這個例子中,假設已經指示投資組合服務添加股票頭寸。它不是直接調用Accounts服務,而是向「Position Added」事件流發佈事件。Accounts微服務已訂閱該事件流,所以它得到通知。它會檢查以確保用戶的賬戶中有足夠的資金。若是是這樣,它會減小用戶賬戶中的資金數量,並將事件發佈到「賬戶更新」事件流。若是用戶在他們的賬戶中沒有足夠的資金,則它能夠將錯誤事件發佈到不一樣的事件流(爲了簡化示例,未示出)。Portfolio微服務訂閱了「賬戶更新」事件流,當它看到Accounts微服務發佈的事件時,
這種類型的體系結構中的異步通訊引入了服務彼此高度分離的好處 - 每一個服務的實例能夠被替換,從新部署或擴展,而不須要其餘微服務關注它們。權衡是事件的異步性質使得更難理解系統將如何執行以及事件流將是什麼。根據生成的事件的順序或種類,系統可能會以意想不到的方式運行。這被稱爲緊急行爲,而且是編排的微服務的開發和測試中的固有挑戰。
有不一樣的異步消息傳遞模式 屬於更普遍的事件驅動的微服務類別。當微服務須要使用異步操做進行編排時,使用異步命令調用模式 - 其中一個微服務須要異步調用另外一個微服務,同時保證第二個微服務接收消息。在此模式中,一般使用隊列交換消息。
RabbitMQ是微服務架構中用於實現此模式的通用框架。當一個微服務須要發佈第二個微服務的事件來處理而後等待從該第二個微服務讀取「回覆」事件時,就會出現這種模式的特定化身。
考慮咱們剛剛討論的Portfolio示例,其中REST API調用告訴Portfolio微服務添加位置。Portfolio服務將事件發佈到要添加的位置,以便處理Accounts微服務,而後等待Accounts服務將回復事件發佈到Account Updated隊列,以便REST API調用能夠返回從該事件接收的數據。爲此示例配置測試方案有兩種不一樣的方法:
第一種方法是建立具備必要隊列的環境,其中部署了Portfolio服務,但未部署Accounts服務。因爲未部署Accounts服務,所以測試方案須要經過在適當的時間從Accounts服務發佈預期事件來模擬Accounts服務的行爲。Parasoft SOAtest測試場景將使用兩個測試構建:一個執行Portfolio服務的REST API,另外一個測試從Accounts服務發佈事件。須要將測試配置爲併發運行,以便在Portfolio服務正在偵聽事件時,來自Accounts服務的事件發佈。
不是經過使用測試來發布其事件來模擬Accounts服務,而是構建可重用的虛擬服務,該服務能夠監聽發佈到Position Added隊列的事件並將結果事件發佈到Account Updated隊列。而後,這個虛擬微服務能夠在可能須要它的多個不一樣測試場景中重用。
第一種方法很簡單,它是一種獨立的測試資產,在測試基礎架構上沒有額外的外部依賴性。第二種方法是可重用的,是對系統真實行爲的更接近的模擬。然而,第二種方法具備構建,部署和管理單獨虛擬資產的成本。
異步命令調用模式的變體是一種微服務,它在隊列中偵聽傳入事件,處理事件,而後在不一樣隊列上發佈後續事件,以便處理一個或多個其餘微服務:
在此示例中,Invoice微服務是須要測試的服務。Payments服務將一個事件發佈到Payment Processed RabbitMQ隊列,以便Invoice服務獲取。Invoice微服務從隊列中讀取事件,建立發票,而後將事件發佈到Invoice Created隊列,以指示Email微服務使用發票向客戶發送電子郵件。要爲Invoice微服務建立測試場景,能夠配置包含兩個RabbitMQ隊列和部署的Invoice微服務的測試環境。能夠構建Parasoft SOAtest測試場景,將付款處理的事件發佈到Payment Processed隊列。而後,該方案訂閱「發票建立」隊列,以驗證發票服務響應是否發佈了正確的發票建立事件。這是一個很是簡單的測試場景,能夠獨立地測試Invoice服務。
當不一樣的源產生大量須要經過公共集線器快速傳遞給不一樣消費者的事件時,使用事件firehose模式。在此模式中,消息經過主題交換(與經過隊列交換消息的異步命令調用模式相反)。用於實現事件firehose模式的通用框架是Apache Kafka框架,它看起來像這樣:
假設咱們想要測試訂閱Kafka主題的單個微服務,處理它接收的事件,而後將其結果發佈到第二個Kafka主題。例如,像這樣:
在此示例中,咱們有一個預測微服務,訂閱了一個天氣數據主題,該主題從許多不一樣的來源收集了大量不一樣的天氣數據。而後,它處理該數據以更新其預測模型,並將預測數據發佈到預測數據主題。在這種狀況下,咱們須要驗證Forecast服務是否將預期事件發佈到一組特定的Weather Data事件的Forecast Data主題。
這能夠經過配置具備兩個Kafka主題和已部署的Forecast服務的測試環境來完成。測試場景首先將必要的事件發佈到Weather Data主題,而後訂閱Forecast Data主題以驗證Forecast服務是否發佈了正確的預測數據事件。須要構建多個不一樣的測試場景,以驗證預測由微服務處理的事件的不一樣類型和順序。
這是一個相對簡單的測試場景。預測微服務與其餘微服務分離的事實具備幸運的反作用,即預測服務的測試也與微服務分離。在這種狀況下,您不須要使用虛擬服務設置複雜的環境 - 您只需建立發佈事件的測試方案並驗證是否在響應中建立了正確的事件。
許多微服務團隊採用持續集成/持續部署(CI / CD)流程來構建,測試和部署容器化微服務,以自動化流程並下降與部署更新相關的風險。
在此過程當中,包含微服務的容器映像會自動建立並部署到測試環境中(一般由Kubernetes 或基於Kubernetes的分發管理,如OpenShift),其中微服務能夠在推送到端到端以前進行驗證。結束測試,最後投入生產。我建議閱讀容器化微服務和設計微服務的CI / CD :持續集成。這兩篇文章都很好地描述了這種過程。
咱們討論過的一些測試模式依賴於依賴微服務使用虛擬服務。這些虛擬服務須要高度組件化而且易於部署,其緣由與它們模擬的微服務是組件化的相同。要使服務虛擬化在這些環境中運行,您須要建立易於部署的容器化虛擬服務。
要建立容器化虛擬服務,您能夠獲取包含Parasoft Virtualize及其全部依賴項的基礎映像,並將其與包含虛擬服務的全部虛擬資產配置的另外一個映像分層。能夠將虛擬服務的新映像做爲容器部署到Docker / Kubernetes環境中,同時將容器用於所測試的微服務及其全部(虛擬化)依賴項。
隨着團隊採用微服務,瞭解如何充分測試它們很是重要。我在這裏討論的消息模式和相關的測試模式並不新鮮,但隨着微服務變得愈來愈廣泛,愈來愈多的應用程序採用微服務範式,使用這些模式的需求也大大增長。
高永亮的筆記大全
一個懂業務的技術人!主要方向「數據庫」、「項目管理」。你們都喊他高哥。個人世界不僅有Coding。還有生活和認知。Just coding it。 一個堅持原創,從不斷更的公衆號。推薦關注!