日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

 

關于單元測試的三個問題

作為一個程序員,或多或少聽說過單元測試,但很多小伙伴還沒有在實際項目中用到。究其原因,可能是對單元測試有一些「誤解」,比如:

  • 寫單元測試需要花費更多的時間,我每天寫產(chǎn)品代碼都要加班,哪來時間寫測試;
  • 寫單元測試收益不大,還不是一樣有bug;
  • 寫單元測試有負擔,改產(chǎn)品代碼的結構,還得去改測試代碼。

先嘗試解答這幾個問題。

寫單元測試會花費更多的時間,這點描述其實不準確。準確地說,寫單元測試需要花費更多「寫代碼的時間」,這點沒什么可說的,畢竟要多寫一些測試代碼。但一個程序員,做一個需求的時候,花在純寫代碼的時間其實不多。你得理以前代碼的邏輯,設計類和方法,然后才是寫代碼,寫完了再手動測試,可能有bug還要去debug,再修復,再測試。「真正寫代碼的時間,其實是很少的」。使用單元測試雖然可能占用了更多寫代碼的時間,但它可以幫你縮短其它時間,「會讓你做這個需求花費的總時間更少」

寫單元測試會有bug嗎?當然可能有了,我們是無法做到真正的bug free的,但是單元測試寫好了,可以顯著減小bug的數(shù)量。因為寫單元測試發(fā)現(xiàn)bug的成本是非常低的,它可以在開發(fā)階段就發(fā)現(xiàn)bug,而且可以測試很多邊界的條件。但如果你「對需求和業(yè)務的認知本來都是有誤」的,這是單元測試解決不了的,自然會產(chǎn)生bug。話說回來,寫單元測試的收益遠不止發(fā)現(xiàn)bug這么簡單,它還具有「代碼文檔」的功能,以及「重構的安全網(wǎng)」存在。甚至它還可以幫你「理需求」「設計代碼」

改產(chǎn)品代碼需要維護對應的測試代碼,這確實是帶來了額外的成本。不過借助編輯器的「重構功能」,可以比較方便地批量修改需要修改的地方,其實代價沒有想象中的那么大。而且重構后,再跑一遍單元測試,看哪些掛掉了,可以double-check你改的產(chǎn)品代碼有沒有問題。如果我們把單元測試當成是「產(chǎn)品代碼的文檔」來看,大概就更能夠接受這個維護的成本了。

為什么需要單元測試?

前面提到,單元測試有很多功能。個人覺得單元測試最大的作用是“代碼文檔”和“重構安全網(wǎng)”。畢竟軟件開發(fā)的漫長過程中,總少不了修修改改。如果沒有足夠的測試,改一段代碼就像是在排地雷,改完后心里也總是打鼓,上線前需要先默默拜個神,生怕觸發(fā)了什么bug。

但如果有足夠的測試(不只是單元測試),改完代碼后可以跑一遍測試,看哪些掛掉了,是不是自己的改動導致的,該怎么修好測試。這樣心里就有底氣多了。

要知道,代碼寫出來是給人看的。而測試比產(chǎn)品代碼更友好,因為它簡單,直白,站在使用者的視角來描述,所以如果想要了解一段產(chǎn)品代碼具有什么功能,看它的單元測試會更直觀,更舒服。

很多團隊會做測試,但絕大多數(shù)測試的工作是在開發(fā)后,由專門的測試同學去負責端到端的測試或者API測試。其實端到端的測試成本是非常大的,尤其是對于某些邊界條件,構造數(shù)據(jù)和場景是非常麻煩的。而且一旦發(fā)現(xiàn)了bug,再去溝通,修改,提交,部署,需要花費很多時間。

而單元測試最大的優(yōu)勢就是“成本低”,想要測試產(chǎn)品代碼的每個分支都比較容易,而且單元測試一般是開發(fā)同學自己寫,可以用最小的時間發(fā)現(xiàn)bug,用最低的成本修改bug。

什么是單元測試?

測試金字塔

并不是所有測試都是單元測試,測試其實分成很多種。業(yè)界比較廣泛傳播的“測試金字塔”描述了它們的區(qū)別和關系:

從零開始寫單元測試

 

測試金字塔

從測試金字塔模型來看,越在底層的測試,覆蓋面應該更廣,成本更低。單元測試處于測試金字塔的最低端,是整個測試金字塔的基礎。

當然了,測試金字塔并不一定只有三層,中間可能會有其它的測試,比如“契約測試”等。

?

還有另一種“菱形測試”模型的說法,即大多數(shù)測試寫在接口測試這一層,而UI測試和單元測試只寫小部分測試。本文不做討論,有興趣的同學可以自行了解一下。

?

單元測試的特點

單元測試就像它的名字一樣,“單元”(Unit),足夠小,足夠快,無依賴。單元測試只測你想測的那部分產(chǎn)品代碼的邏輯,一個單元測試應該只測一個簡單的業(yè)務邏輯。一般來說,運行一個單元測試是很快的,基本上在幾毫秒到幾十毫秒之間。如果有依賴的類,可以mock其他類,消除外部依賴。

什么不是單元測試?

很多同學容易將其他測試與單元測試搞混,最常見的是會啟動Spring上下文的集成測試。比如使用@SpringBootTest注解可以啟動Spring上下文,這可以測試依賴是否正常注入等Spring的功能,但運行一次需要耗費很多時間(因為要啟動Spring上下文),也并不是真正的“單元測試”,因為它依賴了Spring框架。

如何寫單元測試

那具體如何寫單元測試呢?我們業(yè)界有一個叫做「TDD」(測試驅(qū)動開發(fā))的方法論。TDD的核心在于“驅(qū)動”二字,它的理念是從測試視角出發(fā),通過測試驅(qū)動出來產(chǎn)品代碼。而在測試金字塔中,單元測試與開發(fā)人員最息息相關,所以這里的“測試”一般是指的單元測試。

TDD大概分這幾個步驟:

  1. 理清需求
  2. 設計類和方法的出參和入?yún)?/li>
  3. 寫測試代碼
  4. 驅(qū)動出產(chǎn)品代碼
  5. 重構,循環(huán)3-5步。

首先要理清楚需求,因為只有理清楚了需求,才能保證我們使用TDD驅(qū)動出來的代碼是跟業(yè)務期望的一致的。然后第二步是設計類和方法的過程,也稱為Task List。這一步可以設計好類與類之間的關系,方法的出參和入?yún)ⅰF鋵嵅皇褂肨DD也會有前面這兩個步驟,只不過使用TDD的話,可以幫助你更好地從業(yè)務視角出發(fā),先把該設計的東西都設計好,避免直接上手寫代碼,寫到一半的時候覺得不對,再去改。

3-5步其實是一個循環(huán)的過程。因為剛開始寫代碼可能并沒有太注意代碼的格式、風格、性能,一氣呵成寫得比較快,讓測試通過。等測試通過后,可以回過頭來重構一下之前寫的代碼,重構后再跑一遍所有的單元測試,看是否有掛掉的單元測試,以此來檢測重構是否對期望的輸入輸出有影響。

單元測試的結構

一個完整的單元測試,應該分為4個部分:

  1. 聲明和參數(shù)
  2. 準備入?yún)⒑蚼ock
  3. 調(diào)用產(chǎn)品代碼
  4. 驗證,也叫斷言

拿JAVA來說,單元測試框架有幾個,最流行的應該是JUnit和TestNG。筆者使用JUnit多一點,JUnit使用@Test注解在方法上來聲明一個測試。JUnit最新版本是JUnit 5,JUnit 5相較于上一個版本,在參數(shù)化測試方面做了很多改進,這樣我們就不用寫很多個高度相似的測試方法了。

?

關于JUnit 5參數(shù)化測試,大家可以查看官方文檔,也有對應的中文翻譯,很方便閱讀。也可以去我的個人網(wǎng)站搜索《JUnit 5參數(shù)化測試》。

?

一般來說,方法名需要盡可能可讀,它可能比較長,但能夠清晰地表述這個測試的意圖,比如:

@Test
void shouldReturn5WhenCalculateSumGiven2And3() {}
@Test
void should_return_5_when_calculate_sum_given_2_and_3() {}
復制代碼

具體使用駝峰命名法還是下劃線,根據(jù)自己團隊的規(guī)范來就好,盡量所有測試風格保持一致。(個人更喜歡下劃線~)

入?yún)⒁话闶腔绢愋突蛘逷OJO對象,有些參數(shù)可以抽成變量,后面在驗證階段可能用得上。

如果產(chǎn)品代碼有外部依賴,就需要用mock來消除外部依賴。常見的Mock框架有EasyMock、「Mockito」等,大家可以對比一下各個mock框架的區(qū)別,選擇一個合適的。

很多同學剛開始寫單元測試的時候不能理解為什么需要mock,覺得mock比較麻煩,甚至有點多此一舉的感覺。其實不然,mock的意義在于,你「可以保證你的測試只測試了你要測的那部分代碼」。這樣如果測試不通過,你就可以知道一定是要測的那個方法有問題,不可能是外部依賴的問題,這樣才能做到真正的“單元”化,才能保證每個測試足夠小,足夠純粹。

準備好入?yún)⒑蚼ock后,會顯式地調(diào)用一下要測的那個方法,這個一般只有簡單的一行。

最后是驗證,驗證分為好幾種,最常用的是驗證出參是符合自己期望的。也有時候會驗證異常等邊界情況。JUnit等測試框架基本上自己帶了驗證的功能,但API都比較簡單,個人感覺不是特別好用,推薦使用「AssertJ」,功能強大,API用起來也比較舒服。

舉個例子吧:

@Test
void shouldReturnUserWithOrgInfoWhenLoginWithUserId() {
    String userId = "userId";
    String orgId = "orgId";
    User user = UserFactory.getUser(userId);    Org org = OrgFactory.getOrg(orgId);    given(orgService.getOrgById(orgId)).willReturn(org);        UserInfo userInfo = userService.login(userId);        assertEquals(org, userInfo.getOrg());}復制代碼

單元測試常見問題

下面聊一聊單元測試常見的一些問題。

先寫測試還是先寫產(chǎn)品代碼?

都可以。雖然有一種說法是TDD推薦的是先寫測試,再寫實現(xiàn)。但很多剛開始寫單元測試的同學并不習慣這種方式。先寫測試有一個好處,可以讓你在設計代碼的時候從業(yè)務視角去思考,而不是代碼實現(xiàn)視角。大家可以嘗試先寫測試再寫實現(xiàn),體會一下這種感覺。

?

b站上有一個用TDD來實現(xiàn)計算斐波那契數(shù)的視頻,是標準的TDD流程,感興趣的同學可以去看一下,叫《TDD實戰(zhàn)@計算斐波那契數(shù)》

?

寫單元測試需要花費大量額外的時間?

這個其實在文章開篇已經(jīng)討論過了。寫單元測試確實會花費更多的“寫代碼”的時間,但是總的來說,它可以縮短整個需求開發(fā)周期的時間。所以寫單元測試完全是一筆“劃算的生意”。

什么代碼最需要單元測試?

不自信的代碼,邏輯復雜的代碼,重要的代碼。比如工具類、三層架構的Service層、DDD的聚合根和領域服務等,這些都應該寫足夠的單元測試。

對象構造太麻煩?

構造一個合適的入?yún)ο蟊容^麻煩,尤其是有些對象有非常多的參數(shù),如果每個測試都要去從頭構造的話,會讓測試代碼變得非常臃腫,可讀性變差。這個時候可以使用工廠類來批量生產(chǎn)對象。這個工廠類放在測試目錄下,并不會對生產(chǎn)代碼造成影響。前面的例子里面,UserFactory就是一個User對象的工廠類。

返回值為void測什么?

返回值為void,說明方法沒有出參,那方法內(nèi)部必然有一些行為,它可能是「改變了內(nèi)部屬性的值」,也可能是「調(diào)用了某個外部類的方法」

如果是改變內(nèi)部的某個值,那可以通過對象的get參數(shù)來斷言。這在使用DDD后的領域模型是一個問題,因為有可能本來產(chǎn)品代碼不需要暴露出get方法的,但由于測試需要,暴露出了內(nèi)部屬性的get方法。雖然使用反射也可以拿到內(nèi)部屬性的值,但沒有太大必要。權衡利弊,還是暴露領域模型的get方法好一點。

如果是調(diào)用某個外部的方法,可以用verify來驗證是否調(diào)用了某個方法,可以用capture驗證調(diào)用其它方法的入?yún)ⅰ_@樣也可以驗證產(chǎn)品代碼是否如自己預期的設計在工作。

static方法如何mock?

static方法不好mock,需要用特殊的mock框架。比如PowerMock、JMockit。一般來說,Utils類的方法很多是static的,我們用得很多的時間類LocalDateTime,獲取當前時間,也是static的。這個時候需要用專門的mock框架來mock一下。

多線程如何測試?

多線程也不好測試。如果程序簡單,可以用「睡眠」或者CountDownLatch等多線程工具類來輔助測試,等所有線程跑完,再統(tǒng)一驗證。

如果程序相對復雜,需要使用專門的多線程測試框架,比如tempus-fugit、Thread Weaver、MultithreadedTC、以及OpenJDK的jcstress項目等。

關于具體的框架如何使用,以后有時間可以寫一篇常用的注解的介紹。其實官方文檔里面都有寫,大家照著官網(wǎng)寫幾個例子就會了。比較推薦的基礎套餐是junit 5 + mockito + assertj。關于static方法和多線程測試框架,大家有需要的時候再去了解也行。

關于作者

我是Yasin,一個有顏有料又有趣的程序員。

微信公眾號:編了個程

個人網(wǎng)站:https://yasinshaw.com

分享到:
標簽:單元測試
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定