單元測試的前世今生 與sonarqube的愛恨糾葛 寫給小白看,小白可以看到一些技術,會有收穫 大神請留言請吐槽指點一二 謝謝!

 

單元測試,問問自己寫不寫單元測試?

其實,工作10年了,都沒有專門寫單元測試,野路子寫了這麼多代碼,即沒有單元測試,也沒有sonarqube,不知道留下了多少Bug在這10年的職場之路!有沒有在入住酒店的時候,發現系統卡死了,有木有在銀行開戶的時候系統… …很開心是吧!

第一次寫單元測試的時候,老把測試驅動開發混在一起。第一次看到powermock出來的單元測試代碼,都想吐。這代碼看起來真心的“噁心”至極。10行代碼,也許得造100行單元測試代碼出來,這可能說得稍微有些誇張,就是單元測試代碼量超級多的感受。如果要實現100%的單元測試,簡單會是一個極大的挑戰。代碼量會指數級增加。

關鍵詞:Powermock

寫單元測試,我說的是java,我們使用powermock、mock、testng這種東東,相信你知道怎麼去了解更加詳細的信息。這裏就不帖一些沒有態度沒有溫度沒有人文感受的文字過來了。

秀幾行

UserBean user = mock(UserBean.class);when(user.getUserById(anyInt())).thenReturn(new UserBean());doNothing().when(user).sayHello();

這是最常用的幾行代碼,基本上就是依靠他們,模擬所有代碼行爲進行單元測試。

噁心?

是的,第一次見到他們,不噁心纔怪,得一點一點mock,對於靜態類等特殊的成員,還得找法子去mock,把每個分支都覆蓋到,最後實現100%的覆蓋率。

單元測試的意義

之前我的感覺是單元測試是幫我們找出當前代碼問題,而寫完單元測試之後,到沒有這種感覺,反而是,防止今後別人不小心破壞了當前已經驗收通過的代碼。如果按我們寫mock的方式進行全面覆蓋的話,別人只要改變一個邏輯,都可能導致單元測試失敗,從而發現風險。

單元測試的權衡

因爲我們只要求單元測試在service層實現100%的覆蓋,所以我會愛上,單元測試,如果要在bll層,覆蓋的話,我可能會改變哦。bll層太多的細枝末節,mock起來遇到一股意想不到的代碼風暴。而service層則不同,對於我們來講,service層是負責組裝的,mock的時候就能巧妙的實現快速覆蓋,避免mock中常見的特殊的靜態類啊,還可以避免過多的if要覆蓋。如果想要挑戰自己的單元測試實力,那就是去寫bll層的單元測試,嗯,相信是史無前例的挑戰!

單元測試與sonarqube相愛相殺

單元測試要覆蓋所有的邏輯分支,按copy複製再修改修改的寫法,重複代碼會直接捅破sonarqube的底線,直接不給過啊,重複率太高了。寫單元測試的時候,都有種衝突,把sonarqube關掉,哈哈!不關sonarqube,那就得重用重用自己的代碼,不能複雜一口氣複製一遍testcase出來。

一招讓單元測試powermock與sonarqube和平相處

單元測試可以看着源代碼,一點一點mock,遇到一個if就給個開關控制,一路下來,就產生了很多開關,這樣子就能通過參數來控制一個公用的testcase實現全分支覆蓋,同時又不會引起powermock報警。

秀一下僞代碼

@Test[name="登陸失敗-驗證碼錯誤",enable=true]public void login_whenVerifyCodeError_thenFailed(){  login(false,false,false,false,false,verifyMessage);}@Test[name="登陸失敗-帳號鎖定",enable=true]public void login_whenAccoutLocked_thenFaild(){    login(true,false,false,false,false,verifyMessage);}... ...private void login(boolean isVerifyCodeOk,boolean isAccountLocked,...){ when(verifyAgent.check(verifyCode)).thenReturn(isVerifyCodeOk); ....}

這段僞代碼是秀出最近摸索出來的,用來防止單元測試出現大量重複代碼。通過傳參,控制代碼分支走向,達到即能覆蓋到所有支付,又不會惹惱sonarqube.

巧用只在Service層寫單元測試原則

service層寫單元測試,也就是把瑣碎的具體的業務代碼放到bll層,service層保持一種組裝bll業務的對單元測試友好的狀態,就可以巧妙的避免寫複雜的service層單元測試。爲了,能快速搞定單元測試,這個原則可以合理的利用利用。還有一些小經驗:

  1. 儘量不要把些特殊的類丟到Service層來使用,比如一些靜態類,final類,方法什麼 ,可以找靜態類相關的mock方式,但是如果不把他們放進來,是不是直接可以繞過去?是好是壞呢?歡迎指點指點。如果從Service組裝業務的定位來看,是可以的,把業務驗證丟到bll層,這樣子service層拿到一個bll層返回的業務結果,也巧妙的避免了用單元測試最可能出現代碼大爆炸的地方。不好的是,可能在業務細節覆蓋上就失去了精度。這種精度覆蓋的放棄 ,也許也算是一件好事,不然,每寫一點點代碼,都可能導致大量的單元測試代碼成本。
  2. 在service層避免try catch,單元測試不好搞,目前沒有找到好方式把try catch丟給bll層,或者不要try,直接往外丟。往bll層放,也不錯,返回一個明確的結果,就好進行單元測試覆蓋。往外拋,不要try catch。一出現try catch,單元測試覆蓋就顯示尷尬了,有經驗的可以分享分享。
  3. 發現service層不好進行單元測試的,就要思考,這些代碼放在serivce層是否合適了,打包成一個小業務放到bll層。嘻嘻,你會發現,寫單元測試真的好快.都把複雜性繞過去了。醬油黨強力推薦,不要打我~

 

技術島公衆號

技術島公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章