1. 程式人生 > >如何寫好單元測試(php程式猿)

如何寫好單元測試(php程式猿)

phpunit單元測試(demo):https://github.com/qq1060656096/phpunit-test

百度經驗地址:http://jingyan.baidu.com/article/597a0643239f36312b524386.html

很多沒寫個單元測試的朋友,總覺得單元測試很難,還增加了工作了,或者把單元測試環境搭好了,也寫了很多單元測試,越寫越累,感覺程式碼質量沒提高,工作量反而提高很多。我們一起來學習下如何寫好單元測試。

我們分以下7個小點來講解:

1.  為什麼要些單元測試?

2. 單元測試與整合測試的區別?

3. 先些程式碼還是先寫單元測試?

4. 誰來編寫單元測試 ?

5. 如何避免無用的測試 ?

6. 測試程式碼覆蓋率?

7. 單元測試中的"mock仿件"或者我們說的打樁?

 

1. 為什麼要些單元測試?

目的:

1. 提高軟體質量

2. 減少bug

3. 減少重複的工作

4. 安全的重構已有的程式碼

5. 讓開發者對程式穩定性更有信心

重要性:

1. 執行單元測試是為了保證程式碼的行為和我們期望的結果一致。

2. 寫單元測試會增加程式碼工作量,同時也節約了bug修復時間。

3. 如果沒有寫單元測試,沒有發現bug的情況下,程式在測試人員測試的時候才發現問題或者在線上環境(正式環境)使用者使用才發現問題,在去修復bug。開發會花大量的精力去修復bug和走部署流程,測試也會花大量的時間去做了重複的測試。很不划算。

4. 在線上某些場景下bug導致大量的資料丟失,需要花很大精力去修復資料,或者根本沒辦修復資料導致嚴重的後果。

 

2. 單元測試與整合測試區別?

測試粒度不同:單元測試是程式最小的單元,而整合測試是一個功能,一組功能或者整個系統上

單元測試:程式的最小單元。

整合測試:也叫組裝測試或聯合測試,是在單元測試的基礎上,把所有模組按系統設計要求組裝成功能或者系統,實際中程式單元,測試通過了,不能保證程式組裝也能正常的工作,程式某些在區域性反應不出問題,很有可能在全域性或者特殊場景下暴露出問題。

單元測試和整合測試很容易混為一談:因為單元測試和整合測試可以試用相同的工具和框架編寫。

3. 先寫程式碼還是先寫單元測試?

編碼前,要先寫測試,很多沒有寫過單元測試的朋友會想,程式碼都沒有,連測試的物件都沒有,我怎麼寫單元測試?

1. 我們可以通過先話流程圖,寫虛擬碼或者建模來解決這個問題,這樣讓我們站在使用者的角色去開發,儘早的發現問題

2. 避免我們開發完了,某個功能模組遺漏了的情況。

3. 這樣開發出來的程式擴充套件性、維護性很容易理解。

 

4. 誰來編寫單元測試?

單元測試一般由開發員自己些,但是我們自己對自己的程式碼編寫單元測試的情況下,習慣性的往理想情況下編寫,開發員最好不要針對自己的程式碼編寫單元測試。應該有其他開發編寫,這樣減少了bug也提高了開發的水平。

5. 如何避免無用的測試?

1. 只寫必要的測試

編寫自己覺得不靠譜的程式碼,例如業務很複雜自己沒有吃透,以前沒有寫過,感覺會產生無法預料的結果。

 

2. 只寫關鍵的測試

有時候必要的測試我們些不出來,也沒有人知道,我們只能勉強跳過。但是關鍵性的測試不能跳過,關鍵性測試就是:你寫的程式碼的核心洛基。如果你不知道怎麼處理,你知道要保證最終要的那條路線是可以走通的,將來重構的時候,這條路線能確保你不會茫然。

3. 無用的測試

3.1 不要去測試開發語言的標準庫和核心庫,因為這些程式碼都是久經考驗過得。雖然這些會出現小概率的錯誤。(如果你確定是開發語言的標準庫或者核心庫的問題,你應該測試標準庫和核心庫,因為它們都帶有完整的測試用例)

3.2 不要去測試基礎框架和工具方法和外部依賴的有效性,當你遇到這種問題,你應該打樁"mock"。

3.3 你只見過它測試通過,沒有見過它測試失敗,可能這種測試從頭到尾都沒測試任何程式碼,我們應該手動破壞程式碼,以確保幀的覆蓋到了目的碼。

6. 測試程式碼覆蓋率?

我們應該忽略程式碼覆蓋率:就算覆蓋率達到100%,和"靠譜"的程式碼肯能有天壤之別,問題就在於有些公司把程式碼覆蓋率作為考核的標準,這就讓開發很容易就演變成"追求100%程式碼覆蓋率",然後無所不用,連開發都不懂,那就更悲劇了,一群人對著水分極大的程式碼,然後對著"100%程式碼覆蓋率"樂得合不弄嘴想想都難受想哭。

測試中的仿件"mock"或者我們說的打樁?

有時候對被測試的系統進行測試很困難,因為它依賴無法在測試環境中使用的物件、元件、API或者它們不可用。在這種情況下,我們確保測試系統的內部行為有更多的控制性和可見性,我們可以使用仿件"mock"或者打樁。

7. 什麼情況下使用"仿件mock、樁件stubs" ?

1. 外部依賴不存在。

2. 外部依賴不會返回測試需要的結果,或者它有不良的副作用。

3. 如果外部依賴更變,會導致我們的測試失敗。

我們來看一個打樁示例:

1. 我們在編寫單元測試購物車"Cart"類,依賴產品類"Product"和使用者類"User"。

2. 依賴產品類"Product"和使用者類"User"已經測試過了。

3. 依賴的產品類"Product"和使用者類"User"是由他人開發的。

示例問題:

1. 產品類"Product"和使用者類"User"一旦出現問題,不會讓我們誤以為購物車類"Cart"出了問題。

2. 不用為了創造很多前置條件,才能做出斷言。(如果這樣你應該把它放到整合測試)。

3. 在測試購物車時,我們應該避免使用"new Cart($userId, $productId, $quantity)"這種方式,這樣會出現程式中很多地方都去做了重複的查詢,並且影響程式的執行效率,更不利於打樁,我們應該使用這種方式"new Cart(User $user, Product $product, $quantity)"

參考文獻:

https://www.jianshu.com/p/1cb94e6508b8