背景動機
某期優化需要針對通用的HttpClient封裝組件--HttpExecutor在保證上層暴露API不動的前提做較多改動,大致包括以下幾點:
- apache http client 版本升級
- HttpClientBuilder代碼重構
- RequestBuilder代碼重構
- 自定義RetryHandler
- HttpContext擴展
- 自定義HttpRequestInterceptor/HttpResponseInterceptor
代碼很快修改完了,但是如何保證HttpExecutor的行為和以前是一致的呢?很容易就想到是單元測試。因為以前的代碼並未提供組件的單元測試,都是依賴QA同學的黑盒測試完成,現有的單元測試又都是在更上層的HttpDao上,重點是對返回數據的解析邏輯代碼驗證,直接Mock了HttpExecutor的返回結果,完全無法覆蓋底層組件的請求邏輯,因此配合本期優化需要提供HttpExecutor組件的單元測試。
需求分析
先大致分析一下HttpExecutor組件提供的功能:
- 注冊apache http client實例的初始化和銷毀,包含ConnectionManager等apache http client子功能組件;
- 上層入參的轉封裝,以及HttpResponse結果的初步解析封裝(response header、status code、response data);
- 依賴Interceptor對Http請求進行簡單的統計;
- 指定IO異常時的重試功能;
從功能上來分析,我需要的框架/組件需要滿足以下功能:
- 響應延時;
- 異常模擬;
- Response Mock;
- request verify(請求驗證);
- 必須是通過server simulate的方式,而非client stub,即必須真實的發起Http請求;
- 足夠輕量,不必通過獨立進程部署;
作為加分項,最好可以提供以下功能:
- Record & Replay(記錄真實請求自動生成回放配置,生寫代碼有點痛苦);
- 支持json或yaml等非代碼的DSL配置方式;
- 和Junit等單元測試框架集成良好;
- 支持maven plugin;
- 支持版本控制;
選型
從需求分析中必須真實發起請求來看,我的目標就是類似前后端分離開發中常用的API管理平台,這種平台很多,國內的類似小幺雞、YApi、Rap2、Eolinker。但這些平台都必須是作為獨立進程部署,而作為單元測試場景,我需要的足夠輕量的部署方式。
照例先google、baidu、stackoverflow、github、mvnrepository上轉一圈,找到了以下幾篇關聯性較強的文章(倉庫):
- Introduction to MockServer
- Introduction to WireMock
- okhttp/mockwebserver
- Leveling Up Your UI Tests With MockWebServer
- How to mock a web server for unit testing in Java?
- API integration and mocking.Most popular frameworks
- Comparison of API simulation tools
- Compare WireMock and MockServer's popularity and activity
- npm trends:mock-api-server vs mockserver vs mockserver-node vs wiremock-js vs wiremock-standalone
- 微服務下的契約測試(CDC)解讀
- Spring Cloud Contract
從微服務下的契約測試(CDC)解讀中對契約測試、單元測試、接口測試區別描述中可以發現,契約測試完全能滿足甚至超出我的需求,因此下面的框架選型也從契約測試的方向來出發。
根據文章推薦,篩選出mock-server、okhttp/mockwebserver、WireMock。
Framework | 部署方式 | 抓取回放請求 | 代理服務模式 | Https/SSL | Http2 | 故障模擬 | 多語言支持 | 非代碼配置 | 生態(其他框架集成) | Http Log | Response模板 |
---|---|---|---|---|---|---|---|---|---|---|---|
mock-server | jar包集成/獨立war包部署/Maven Plugin/Node.js Module/Grunt Plugin/Docker/Kubernetes/Homebrew 等,詳見Running Mock Server | 支持 | 支持 | 支持 | 支持 | 支持響應延時以及500等錯誤響應模擬 | 支持多語言client(java、ruby、node) | json文件配置 | - | 支持 | 支持 |
okhttp/mockwebserver | jar包集成 | 不支持 | 不支持 | - | 支持 | 支持模擬慢速網絡環境以及500等錯誤響應模擬 | 支持 | json文件配置 | OKHttp | 不支持 | 不支持 |
WireMock | jar包集成/獨立war包部署 | 支持 | 支持 | 支持 | jre8版本支持 | 支持響應延時以及500等錯誤響應模擬 | Node.js | json文件配置 | spring-cloud-contract | 支持 | 支持 |
功能特性對比
就支持的功能集來看,okhttp/mockwebserver最弱,WireMock和mock-server兩者支持的特性大體相同,但是mock-server支持更多種語言和更多的部署環境,而WireMock則有Spring Cloud Contract的光環加持。
架構依賴對比
okhttp/mockwebserver本身就是OKHttp的mock組件,完全是原生的實現,除了Junit幾乎沒有其他依賴,是3個框架里最輕量的,詳見mockwebserver/4.2.2。
mock-server使用netty作為http server,最大的依賴項就是netty,其他還有一些guava、commons-collection4、jackson等依賴,詳見mockserver-core/5.6.1。
WireMock使用jetty作為http server,是典型的servlet架構,其他還依賴guava、jackson、httpclient等,詳見wiremock-jre8/2.25.0。
流行度對比
google trends結果顯示WireMock更流行,而npm trends的結果正好相反,npm trends上mock-server的流行度可謂完全碾壓WireMock,可能和mock-server對多語言的支持以及豐富的部署環境支持有關。
總結
我們知道框架選型永遠都是根據選型人員、代碼現狀、需求場景來決定的,因此我這里只做推薦,不說結論。
如果你只是需要簡單的HTTP Server Simulator輔助業務邏輯測試,無需SSL協議支持,那我推薦你使用okhttp/mockwebserver,功能夠用,十分輕量,而且是OKHttp的組件,如果是Android開發那使用正好(Android上OKHttp使用率碾壓HttpClient)。
如果你已經有很多Http API在運行,希望使用Record & Replay簡化Mock DSL的編寫,那么mock-server和WireMock都能滿足你。
如果你的測試場景包含UI/UX測試,那支持node.js的mock-server對前端開發更為友好。又或者你的真實server是netty,不想引入servlet架構。
如果你是單純的Java API測試,並且你還使用了Spring Cloud技術棧,那么WireMock和Spring Cloud Contract是很合適的選擇。
最后,附上一篇自己實現Mock Server的參考文檔Using Sun Java 6 HttpServer to write a functional HTTP test 。