微服務和傳統的單塊應用相比,在測試策略上,會有一些不太一樣的地方。簡單來說,在微服務架構中,測試的層次變得更多,而且對環境的搭建要求更高。比如對單塊應用,在一個機器上就可以setup出所有的依賴,但是在微服務場景下,由於依賴的服務往往很多,要搭建一個完整的環境非常困難,這對團隊的DevOps的能力也有比較高的要求。
相對於單塊來說,微服務架構具有以下特點:
- 每個微服務在物理上分屬不同進程
- 服務間往往通過RESTful來集成
- 多語言,多數據庫,多運行時
- 網絡的不可靠特性
- 不同的團隊和交付周期
上述的這些微服務環境的特點,決定了在微服務場景中進行測試自然會面臨的一些挑戰:
- 服務間依賴關系復雜
- 需要為每個不同語言,不同數據庫的服務搭建各自的環境
- 端到端測試時,環境准備復雜
- 網絡的不可靠會導致測試套件的不穩定
- 團隊之間的溝通成本
測試的分層
相比於常見的三層測試金字塔,在微服務場景下,這個層次可以被擴展為5層(如果將UI測試單獨抽取出來,可以分為六層)。
- 單元測試
- 集成測試
- 組件測試
- 契約測試
- 端到端測試
和測試金字塔的基本原則相同:
- 越往上,越接近業務/最終用戶;越往下,越接近開發
- 越往上,測試用例越少
- 越往上,測試成本越高(越耗時,失敗時的信息越模糊,越難跟蹤)
單元測試
單元測試,即每個微服務內部,對於領域對象,領域邏輯的測試。它的隔離性比較高,無需其他依賴,執行速度較快。
對於業務規則:
- 商用軟件需要License才可以使用,License有時間限制
- 需要License的軟件在到期之前,系統需要發出告警
![]() |
上面這個例子就是一個非常典型的單元測試,它和其他組件基本上沒有依賴。即使要測試的對象對其他類有依賴,我們會Stub/Mock的手段來將這些依賴消除,比如使用mockito/PowerMock。
單元測試注意點:
- 為功能的每個部分而不是每個函數編寫測試
- 不痴迷於代碼覆蓋率,而是專注於測試有風險的代碼
- 最小化Mock模擬代碼
- 確保您的測試可能會失敗
- 將不確定性排除在測試之外(如果系統中存在不確定性,那么應該保證固定的邏輯不會出錯,對於不確定性的邊緣情況應該通過其它方式保證,比如開發、測試人員、尋找更穩定的類庫等。)
這將使您的系統更加穩定,另外經過良好測試的軟件讓您可以自信地進行更改和快速部署。
集成測試
系統內模塊(一個模塊對其周邊的依賴項)間的集成,系統間的集成都可以歸類為集成測試。比如
- 數據庫訪問模塊與數據庫的集成
- 對外部service依賴的測試,比如對第三方支付,通知等服務的集成
集成測試強調模塊和外部的交互的驗證,在集成測試時,通常會涉及到外部的組件,比如數據庫,第三方服務。這時候需要盡可能真實的去與外部組件進行交互,比如使用和真實環境相同類型的數據庫,采用獨立模式(Standalone)的WireMock來啟動外部依賴的RESTful系統。
通常會用來做模擬外部依賴工具包括:
其中,mountbank還支持Socket級別的Mock,可以在非HTTP協議的場景中使用。
組件測試
貫穿應用層和領域層的測試。不過通常來說,這部分的測試不會訪問真實的外部數據源,而是使用同schema的內存數據庫,而且對外部service的訪問也會使用Stub的方式:
- 內存數據庫
- Stub外部服務(WireMock)
- RestAssured
比如使用h2來做內存數據庫,並且自動生成schema。使用WireMock來Stub外部的服務等。
![]() |
如果使用Spring,還可以通過profile來切換不同的數據庫。比如下面這個例子中,默認的profile會連接數據庫jigsaw,而integration的profile會連接jigsaw_test數據庫:
![]() |
組件測試會涉及到的組件包括:
- URL路由
- 序列化與反序列化
- 應用對領域層的訪問
- 領域層對數據的訪問
- 數據庫訪問層
前后端分離
除了后端的測試之外,在目前的前后端分離場景下,前端的應用越來越復雜,在這種情況下,前端的組件測試也是一個測試的重點。
一個前端應用至少包括了這樣一些組件:
- 前端路由
- 模板
- 前端的MVVM
- 攔截器
- 事件的響應
要確保這些組件組合起來還能如預期的執行,相關測試必不可少。這篇文章詳細討論了前后端分離之后的測試及開發實踐。
契約測試
在微服務場景中,服務之間會有很多依賴關系。根據消費者驅動契約,我們可以將服務分為消費者端和生產者端,通常消費者自己會定義需要的數據格式以及交互細節,並生成一個契約文件。然后生產者根據自己的契約來實現自己的邏輯,並在持續集成環境中持續驗證。
Pact已經基本上是消費者驅動契約(Consumer Driven Contract)的事實標准了。它已經有多種語言的實現,Java平台的可以使用pact-jvm及相應的maven/gradle插件進行開發。
- pact/pact-jvm
- pact-broker
(圖片來源:Why you should use Consumer-Driven Contracts for Microservice integration tests)
通常在工程實踐上,當消費者根據需要生成了契約之后,我們會將契約上傳至一個公共可訪問的地址,然后生產者在執行時會訪問這個地址,並獲得最新版本的契約,然后對着這些契約來執行相應的驗證過程。
一個典型的契約的片段是這樣的(使用pact):
![]() |
端到端測試
端到端測試是整個微服務測試中最困難的,一個完整的環境的創建於維護可能需要花費很大的經歷,特別是當有多個不同的團隊在獨立開發的場景下。
另一方面,從傳統的測試金字塔來看,端到端測試應該覆蓋那些業務價值最高的Happy Path。也就是說,端到端測試並不關注異常場景,甚至大部分的業務場景都不考慮。要做到這一點,需要在設計測試時,從最終用戶的角度來考慮,通過用戶畫像和User Journey來確定測試場景。
在端到端測試中,最重要的反而不是測試本身,而是環境的自動化能力。比如可以通過一鍵就可以將整個環境provision出來:
- 安裝和配置相關依賴
- 自動將測試數據Feed到數據庫
- 自動部署
- 服務的自動重啟
隨着容器技術和容器的編排技術的成熟,這部分工作已經可以比較好的自動化,依賴的工具包括:
- Docker
- Rancher
一個典型的流程是:
- 搭建持續發布流水線
- 應用代碼的每一次提交都可以構建出docker鏡像
- 將docker鏡像發布在內部的docker-hub上
- 觸發部署任務,通過rancher的upgrade命令將新的鏡像發布
- 執行端到端測試套件
端到端測試還可以細分為兩個不同的場景:
- 沒有用戶交互的場景,如一系列的微服務組成了一個業務API
- 有用戶交互的場景
UI測試
最頂層的UI測試跟傳統方式的UI測試並無二致。我們可以使用BDD與實例化需求(Specification By Example)的概念,從用戶使用的角度來描述需求,以及相關的驗收條件。這里我們會使用WebDriver來驅動瀏覽器,並通過諸如Capybara等工具來模擬用戶的操作。
- BDD工具:Cucumber
- Web應用驗收測試工具:Capybara
- Page Object的DSL工具:Site_prism
https://blog.csdn.net/qq_19674905/article/details/78053458?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control