<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          什么是單元測試?為什么要做?

          共 3905字,需瀏覽 8分鐘

           ·

          2022-03-23 11:10

          點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)

          什么是UT?

          UT(Unit Test)即單元測試

          UT有什么價(jià)值?

          大部分的開發(fā)都不喜歡寫UT,原因無非以下幾點(diǎn):

          1. 產(chǎn)品經(jīng)理天天催進(jìn)度,哪有時(shí)間寫UT
          2. UT是測試自己的代碼,自測?那要QA何用?
          3. 自測能測出bug?都是基于自身思維,就像考試做完第一遍,第二遍檢查一樣,基本檢查不出什么東西
          4. UT維護(hù)成本太高,投入產(chǎn)出比太低
          5. 不會寫UT

          總之有無數(shù)種理由不想寫UT,作為工作不到三年的菜鳥深有體會。之前在點(diǎn)評工作的時(shí)候,團(tuán)隊(duì)的“UT”都集中于RPC的服務(wù)端。

          為啥帶雙引號?因?yàn)镽PC的服務(wù)端沒有頁面可以功能測試,部署到測試環(huán)境測試太麻煩,只能寫UT了。在這個(gè)場景下我認(rèn)為叫“驗(yàn)證”更合適,驗(yàn)證不等于測試。驗(yàn)證往往只寫主邏輯是否通過,且就一個(gè)Case,且沒有Assert,有的是System.out。

          本人實(shí)習(xí)的時(shí)候做測試的,那時(shí)候知道一個(gè)測試模型。如下圖:

          (圖一)

          圖的意思就是越底層做的測試效果越好,越往上則越差。也就是說大部分公司現(xiàn)在做的功能測試其實(shí)是效果最差的一種測試方式。另外,QA界有個(gè)現(xiàn)場:大家都知道功能測試沒技術(shù)含量,那如何使自己突出呢?答案就是:自動化測試。現(xiàn)實(shí)是沒幾個(gè)公司能做好自動化測試, 業(yè)界做的比較好的百度算一個(gè)。

          那么為啥自動化測試這么難做的?在這個(gè)模型當(dāng)中,越往上黑盒越大,自動化測試難度就越大。這句話反過來就是越往下自動化測試就越好做?沒錯(cuò),UT其實(shí)是最容易實(shí)現(xiàn)且效果最好的自動化測試。所以在很多公司出現(xiàn)一種現(xiàn)場:QA寫UT。

          原因總結(jié)一下就兩點(diǎn):開發(fā)不愿意寫UT,QA想自動化測試解放自己。以上的模型只是理論上說明UT具有巨大的價(jià)值,但是真的如此么?我只想說,只有真正嘗到UT的好處的甜頭才會意識到UT的價(jià)值。

          Unit Test & Intergration Test

          單元測試和集成測試的界線我相信大部分開發(fā)也是不清晰的。個(gè)人理解單元測試針對于一塊業(yè)務(wù)邏輯最小的單元,太抽象。物理上可以簡單理解為一個(gè)類的方法, 可以是public方法也可以是private方法。一個(gè)單元測試不應(yīng)該包含外部依賴的邏輯,反之就是集成測試了。

          問題的核心就在于此。最新面試題整理好了,點(diǎn)擊Java面試庫小程序在線刷題。

          一個(gè)service的一個(gè)接口實(shí)現(xiàn)可能依賴很多第三方:

          1.本地其它的service

          2.dao調(diào)用

          3.rpc調(diào)用

          4.微服務(wù)調(diào)用。

          如下圖:

          (圖二)

          也就是說你的單元測試,真正調(diào)用了外部依賴那就是集成測試。這其實(shí)很常見對不?我們先說這種情況下如何集成測試。Spring Boot 單元測試教程推薦你看下。

          Local Integration Test

          本地集成測試也就是說不依賴與其他進(jìn)程。包括:service依賴其他本地service或者dao的情況。在講述如何集成測試之前,我們先理一下測試模型,測試主要包含三塊內(nèi)容:1.數(shù)據(jù)準(zhǔn)備 2.執(zhí)行邏輯 3.輸出驗(yàn)證。

          第一步:數(shù)據(jù)準(zhǔn)備

          在本地集成測試?yán)铮瑪?shù)據(jù)來源基本上來自于dao,dao來自于sql。也就是在執(zhí)行一個(gè)case之前,執(zhí)行一些sql腳本,數(shù)據(jù)庫則使用h2這類memory database, 切記不要依賴公司測試環(huán)境的db。

          推薦一個(gè) Spring Boot 基礎(chǔ)教程及實(shí)戰(zhàn)示例:https://github.com/javastacks/spring-boot-best-practice

          下圖是使用spring-test框架的一個(gè)case,可以在case執(zhí)行之前準(zhǔn)備我們所需要的各種數(shù)據(jù),另外在執(zhí)行完case之后,執(zhí)行clean.sql腳本來清理臟數(shù)據(jù)。這里也說明一個(gè)case的執(zhí)行環(huán)境是完全獨(dú)立的,case之間互不干擾,這很重要。

          (圖三)
          第二步:執(zhí)行邏輯最簡單,就是調(diào)用一下我們測試的方法即可
          第三步:驗(yàn)證

          集成測試一般是調(diào)用service,或者dao的接口驗(yàn)證。

          舉個(gè)例子:CRUD操作的集成測試

          1. 調(diào)用C接口
          2. 調(diào)用R接口,驗(yàn)證C成功
          3. 調(diào)用U接口
          4. 調(diào)用R接口,驗(yàn)證U成功
          5. 調(diào)用D接口
          6. 調(diào)用R接口,驗(yàn)證D成功
          Remote Integration Test

          假設(shè)我們一個(gè)service實(shí)現(xiàn)依賴某個(gè)RPC Service

          點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)

          第一步:數(shù)據(jù)準(zhǔn)備

          跑到別人家的數(shù)據(jù)庫插幾條數(shù)據(jù)?或者跟PRC Service的Owner商量好,搭一個(gè)測試環(huán)境供我們測試?有些公司還真有專門的自動化測試環(huán)境,那么即使有測試環(huán)境,那如何實(shí)現(xiàn)各種case場景下,第三方Service很配合的返回?cái)?shù)據(jù)給我們?想想都蛋疼。

          第二步:執(zhí)行方法

          假設(shè)我們成功的解決了第一步中的問題,皆大歡喜。現(xiàn)在來看第二步,假設(shè)我們的service里面調(diào)用了另一個(gè)RPC Service創(chuàng)建了很多數(shù)據(jù),跑了無數(shù)次case,結(jié)果....RPC Service對應(yīng)的數(shù)據(jù)庫都是我們的臟數(shù)據(jù),如何清理?而且他們敢隨便刪數(shù)據(jù)嗎?想想也蛋疼。

          第三步:輸出驗(yàn)證

          假設(shè)我們又愉快的解決了第二步中的問題。現(xiàn)在來看第三步,假設(shè)我們的方法執(zhí)行最終輸出是創(chuàng)建了一個(gè)訂單,訂單當(dāng)然是調(diào)用訂單Service接口了,那么我們?nèi)绾悟?yàn)證訂單是否成功創(chuàng)建了呢?

          或許可以調(diào)用訂單Service查詢訂單的接口來驗(yàn)證。很明顯大多數(shù)情況下并沒有這么完美。想想也蛋疼呀。通過以上分析,Local Integration Test是可行的,Remote Integration Test基本不可行。

          那么有沒有什么辦法解決呢?答案就是Mock

          • 第一步:Mock RPC Service 想返回什么數(shù)據(jù)就返回什么數(shù)據(jù)
          • 第二步:還是Mock接口,想調(diào)用幾次就調(diào)用幾次
          • 第三步:這一步等到下面講完單元測試就明白了
          Unit Test

          上面我們談到Mock可以解決外部依賴的問題,現(xiàn)在有很多Mock的開源框架比如:mockito。那么問題來了,既然我們可以mock第三方遠(yuǎn)程依賴,為何不mock dao、local service呢?

          沒錯(cuò)外部依賴全部mock掉,就是單元測試了。因?yàn)槲覀冎魂P(guān)心所測試的方法的業(yè)務(wù)邏輯,也就是真正高內(nèi)聚的邏輯單元了。如下圖:

          (圖四)

          好處如下:

          1. 沒有什么數(shù)據(jù)是造不出來的,通通返回Mock的對象
          2. 代碼中的異常處理代碼,也可以通過mock接口,使之拋出異常
          3. 不產(chǎn)生任何臟數(shù)據(jù)
          4. 跑case更快了,因?yàn)椴挥脝诱麄€(gè)項(xiàng)目,相當(dāng)于Main方法

          有人會說,都mock了還測試個(gè)蛋蛋。

          這就是對于單元測試的理解了,單元測試應(yīng)該只針對于目標(biāo)方法的業(yè)務(wù)邏輯測試,dao、其它service應(yīng)該在它們自身的單元測試去測試。對于依賴的第三方,我們應(yīng)該信任它們能正確的完成我們所預(yù)期的。這句話很難理解對不對?

          舉幾個(gè)例子

          推薦一個(gè) Spring Boot 基礎(chǔ)教程及實(shí)戰(zhàn)示例:

          https://github.com/javastacks/spring-boot-best-practice

          例子一:方法的最后是執(zhí)行dao的create操作,那么該如何驗(yàn)證?

          我們應(yīng)該驗(yàn)證的內(nèi)容是:

          1. dao的create方法被調(diào)用了
          2. 調(diào)用次數(shù)是對的
          3. 調(diào)用參數(shù)也是對的

          沒錯(cuò),只要這三個(gè)驗(yàn)證通過,那么這個(gè)case執(zhí)行就是通過的。因?yàn)槲覀兿嘈興ao的create操作能正確的完成我們所預(yù)期的,只要我們調(diào)用了正確的次數(shù)并且參數(shù)都是對的。

          dao的執(zhí)行的正確性保證是在該dao的單元測試做的。在Remote Integration Test里面第三步驗(yàn)證道理是一樣的,我們應(yīng)該驗(yàn)證RPC接口被調(diào)用了且次數(shù)和參數(shù)都是對的,那么我們的case就算通過了,至于,RPC服務(wù)端是否正確執(zhí)行是它們的事情不是我們所關(guān)心的。Mockito框架的verify接口就是做這件事情的。如果你理解了上述內(nèi)容,那么你就開竅了,UT不在變得這么難寫。

          什么時(shí)候用單元測試,什么時(shí)候用集成測試?

          在本人的實(shí)踐中摸索發(fā)現(xiàn),對于簡單的業(yè)務(wù),比如crud型的瘦service,比較適合于集成測試。以下情況適合于單元測試:

          1. Util類
          2. 含有遠(yuǎn)程調(diào)用的方法
          3. 輸入少,業(yè)務(wù)邏輯復(fù)雜的方法
          4. 需要異常處理的方法

          case細(xì)到什么程度為好?

          這個(gè)問題也是比較經(jīng)典的,一個(gè)方法要是所有的路徑都覆蓋到,那么要寫很多的case,說真的累死人。

          我的建議是兩個(gè)原則:

          1、核心邏輯,容易出錯(cuò)的邏輯一定要覆蓋到

          2、根據(jù)自己的時(shí)間。沒必要寫的非常多,畢竟case維護(hù)成本很高,業(yè)務(wù)邏輯一改,case得跟著改。

          總結(jié)

          本人目前在從事于開源項(xiàng)目(Apollo(配置中心) )研發(fā),開源項(xiàng)目對代碼質(zhì)量要求相對來說高一些,UT當(dāng)然是很重要的一環(huán)。剛開始也不會寫UT,當(dāng)然態(tài)度上也不重視UT。

          老大的代碼UT覆蓋率很高,抱著對開源負(fù)責(zé)的態(tài)度慢慢接受學(xué)習(xí)UT,到后來嘗了幾次甜頭后,發(fā)現(xiàn)UT真的很實(shí)用,價(jià)值也很高,但是很遺憾UT被大部分開發(fā)所忽略。當(dāng)然本人對UT的理解、實(shí)踐還不夠,仍需繼續(xù)實(shí)踐模式。

          最后說一句:當(dāng)開發(fā)完功能,跑完UT,你可以放心的上線了的時(shí)候,你的UT就成功了。








          Spring Cloud 爆高危漏洞,趕緊修復(fù)!
          2021 年發(fā)生的 10 件技術(shù)大事!!
          23 種設(shè)計(jì)模式實(shí)戰(zhàn)(很全)
          Spring Boot 保護(hù)敏感配置的 4 種方法!
          再見單身狗!Java 創(chuàng)建對象的 6 種方式
          阿里為什么推薦使用 LongAdder?
          AnotherRedisDesktopManager 開始收費(fèi)了?
          別再寫爆爆爆炸類了,試試裝飾器模式!
          程序員精通各種技術(shù)體系,45歲求職難!
          Spring Boot 3.0 M1 發(fā)布,正式棄用 Java 8
          Spring Boot 學(xué)習(xí)筆記,這個(gè)太全了!



          關(guān)注Java技術(shù)棧看更多干貨



          獲取 Spring Boot 實(shí)戰(zhàn)筆記!
          瀏覽 35
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  自拍偷拍激情网 | 婷婷五月成人网 | 成人无码视频在线观看 | 大大香蕉伊人网 | 精品啪啪啪 |