\n * 15位:6位地址碼+6位出生年月日(900101代表1990年1月1日出生)+3位順序碼\n * 18位:6位地址碼+8位出生年月日(19900101代表1990年1月1日出生)+3位順序碼+1位校驗碼\n * 順序碼奇數分給男性,偶數分給女性。\n * @author 公衆號:Java老K\n * 個人博客:www.javakk.com\n */\npublic class IDNumberUtils {\n /**\n * 通過身份證號碼獲取出生日期、性別、年齡\n * @param certificateNo\n * @return 返回的出生日期格式:1990-01-01 性別格式:F-女,M-男\n */\n public static Map
Spock單元測試框架實戰指南一Spock是什麼?它和JUnit有什麼區別?
{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是Spock系列的第一篇文章,整個專輯會介紹Spock的用途,爲什麼使用Spock?它能給我們帶來什麼好處?它和JUnit、JMock、Mockito有什麼區別?我們平時寫單元測試代碼的常見問題和痛點,Spock又是如何解決的,Spock的代碼怎麼編寫以及Spock的優勢和缺點等內容,讓大家對Spock有個客觀的瞭解。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Spock是什麼?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e9/e974a4d7dab15d5a52a0aa3390e81241.jpeg","alt":"image","title":"image","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"斯波克是國外一款優秀的測試框架,基於","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"BDD思想","attrs":{}},{"type":"text","text":",功能強大,能夠讓我們的測試","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"代碼規範","attrs":{}},{"type":"text","text":"化,結構","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"層次清晰","attrs":{}},{"type":"text","text":",結合","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"groovy動態語言","attrs":{}},{"type":"text","text":"的特點以及自身提供的各種標籤讓編寫測試代碼更加","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"高效","attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"簡潔","attrs":{}},{"type":"text","text":",提供一種通用、簡單、結構化的描述語言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"引用官網的介紹如下(","attrs":{}},{"type":"link","attrs":{"href":"http://javakk.com/redirect/aHR0cDovL3Nwb2NrZnJhbWV3b3JrLm9yZw==","title":null},"content":[{"type":"text","text":"http://spockframework.org","attrs":{}}]},{"type":"text","text":")","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/22/22680a59dbbf6e85ae0a7eb3ebc66b17.png","alt":"image","title":"image","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/21/212bc60397df79cd8c18c2c6273a2e91.png","alt":"image","title":"image","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“ Spock是一個Java和Groovy應用程序的測試和規範框架。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它之所以能在人羣中脫穎而出,是因爲它優美而富有表現力的規範語言。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"斯波克的靈感來自JUnit、RSpec、jMock、Mockito、Groovy、Scala、Vulcans ”","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單說Spock的特點如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們的測試代碼更規範,內置多種標籤來規範單測代碼的語義,從而讓我們的測試代碼結構清晰,更具可讀性,降低後期維護難度","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提供多種標籤,比如: ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"where","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"with","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"thrown","attrs":{}}],"attrs":{}},{"type":"text","text":"... 幫助我們應對複雜的測試場景","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再加上使用groovy這種動態語言來編寫測試代碼,可以讓我們編寫的測試代碼更簡潔,適合敏捷開發,提高編寫單測代碼的效率","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遵從BDD行爲驅動開發模式,不單是爲了測試覆蓋率而測試,有助於提升代碼質量","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"IDE兼容性好,自帶mock功能","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"爲什麼使用Spock? Spock和JUnit、JMock、Mockito的區別在哪裏?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"收到現有的單測框架比如junit、jmock、mockito都是相對獨立的工具,只是針對不同的業務場景提供特定的解決方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"Junit單純用於測試,不提供mock功能","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"微服務已經是互聯網公司的主流技術架構,大部分的系統都是分佈式,服務與服務之間一般通過接口的方式交互,甚至服務內部也劃分成多個module,很多業務功能需要依賴底層接口返回的數據才能繼續剩下的流程,或者從數據庫/Redis等存儲設備上獲取,或是從配置中心的某個配置獲取。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣就導致如果我們想要測試代碼邏輯是否正確,就必須把這些依賴項(接口、Redis、DB、配置中心...)給mock掉。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果接口不穩定或有問題則會影響我們代碼的正常測試,所以我們要把調用接口的地方給","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"模擬","attrs":{}},{"type":"text","text":"掉,讓它返回指定的結果(提前準備好的數據),這樣才能往下驗證我們自己的代碼是否正確,符合預期邏輯和結果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"JMock或Mockito雖然提供了mock功能,可以把接口等依賴屏蔽掉,但不提供對靜態類靜態方法的mock,PowerMock或Jmockit雖然提供靜態類和方法的mock,但它們之間需要整合(junit+mockito+powermock),語法繁瑣,而且這些工具並沒有告訴你“","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"單元測試代碼到底應該怎麼寫?","attrs":{}},{"type":"text","text":"”","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"工具多了也會導致不同的人寫出的單元測試代碼五花八門,風格迥異。。。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spock通過提供規範描述,定義多種標籤(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"given","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"when","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"then","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"where","attrs":{}}],"attrs":{}},{"type":"text","text":"等)去描述代碼“應該做什麼”,輸入條件是什麼,輸出是否符合預期,從語義層面規範代碼的編寫。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spock自帶Mock功能,使用簡單方便(也支持擴展其他mock框架,比如power mock),再加上groovy動態語言的強大語法,能寫出簡潔高效的測試代碼,同時更方便直觀的驗證業務代碼行爲流轉,增強我們對代碼執行邏輯的可控性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景和初衷","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"網上關於Spock的資料比較簡單,包括官網的demo,無法解決我們項目中的複雜業務場景,需要找到一套適合自己項目的成熟解決方案,所以覺得有必要把我們項目中使用Spock的經驗分享出來, 幫助大家提升單測開發的效率和驗證代碼質量。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在熟練掌握Spock後我們項目組整體的單測開發效率提升了50%以上,代碼可讀性和維護性都得到了改善和提升。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"適合人羣","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫Java單元測試的開發小夥伴和測試同學,所有的演示代碼運行在IntelliJ IDEA中,spring-boot項目,基於Spock 1.3-groovy-2.5版本","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Spock如何解決傳統單元測試開發中的痛點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這篇主要講下我們平時寫單元測試過程中遇到的幾種常見問題,分別使用JUnit和Spock如何解決,通過對比的方式給大家一個整體認識。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"一. 單元測試代碼開發的成本和效率","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"複雜場景的業務代碼,在分支(","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"if/else","attrs":{}}],"attrs":{}},{"type":"text","text":")很多的情況下,編寫單測代碼的成本會相應增加,正常的業務代碼或許只有幾十行,但爲了測試這個功能,要覆蓋大部分的分支場景,寫的測試代碼可能遠遠不止幾十行","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉個我們生產環境前不久發生的一起事故:有個功能上線1年多一直都正常,沒有出過問題,但最近有個新的調用方請求的數據不一樣,走到了代碼中一個不常用的分支邏輯,導致了bug,直接拋出異常阻斷了主流程,好在調用方請求量不大。。。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"估計當初寫這段代碼的同學也認爲很小几率會走到這個分支,雖然當時也寫了單元測試代碼,但分支較多,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"剛好漏掉了這個分支邏輯的測試,給日後上線留下了隱患","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這也是我們平時寫單元測試最常遇到的問題:要達到分支覆蓋率高要求的情況下,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"if/else","attrs":{}}],"attrs":{}},{"type":"text","text":"有不同的結果,傳統的單測寫法可能要多次調用,才能覆蓋全部的分支場景,一個是寫單測麻煩,同時也會增加單測代碼的冗餘度","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然可以使用junit的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"@parametered","attrs":{}}],"attrs":{}},{"type":"text","text":"參數化註解或者dataprovider的方式,但還是不夠方便直觀,而且如果其中一次分支測試case出錯的情況下,報錯信息也不夠詳盡。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如下面的示例演示代碼,根據輸入的身份證號碼識別出生日期、性別、年齡等信息,這個方法的特點就是有很多","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"if...else...","attrs":{}}],"attrs":{}},{"type":"text","text":"的分支嵌套邏輯","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 身份證號碼工具類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.