老李分享 單元測試的 5 個錯誤

2022-07-27 19:24:14 字數 2369 閱讀 8903

當我第一次聽說可以使用框架比如junit來進行單元測試的時候,我驚嘆這真是乙個簡單而強大的概念。它取代了隨機測試,使你可以儲存你的測試**,並按照需要隨時執行它們。按照我的理解,關於單元測試並沒有多少產生誤解的可能。但是過去的幾年中,我確實見過幾種或多或少不太正確的單元測試使用方式。這裡按照重要程度,列出5條:

1. 跟協作邏輯一起來測試演算法。如果跟協作邏輯**分離開來,那麼演算法邏輯是最容易測試的(參見選擇性單元測試 – 代價和好處)。否則在你的邏輯被測試之前,你就不得不先進行諸如通過任務佇列提交乙個任務之類的工作。 任務佇列部分只會使事情變得複雜。除非你想測試任務佇列本身,否則你就應當把呼叫run方法時所執行的邏輯剝離開來,並對它進行單獨測試。那樣,不論是編碼還是測試都會更易於編寫和管理。

2. mock測試太多。也許單元測試的最大好處就是它迫使你編寫能夠獨立測試的**。也就是說,你的**會變得模組化。當你把你要處理的物件的周圍的一切都模擬了,就沒有什麼能迫使你去把各部分分離開來。你會發現這樣寫出的**,你很難在外圍新增獨立的部分 – 因為所有東西都糾纏在一起。bill wake最近發推說: 」真是諷刺 – 模擬測試框架越強大,你在改進設計時所感受到的壓力就會越小。」

3. 不使用斷言。有時我會看到一些測試,裡面建立了乙個物件,呼叫了一些方法,然後,就沒有然後了。也許它是在迴圈裡這樣做的,而且在建立和呼叫上會有些差異。但是,卻沒有用斷言來做任何檢查。這就完全失去了意義 – 沒有檢查你的**是否按照預期進行工作的。當然,**是執行了,但是僅此而已。如果丟擲了乙個異常,我們會注意到它,但是卻不會驗證其它任何事情。

4. 在測試**中遺留print語句。我把這視為手工測試的後遺症 – 你希望看到物件的值來判斷它們是否正確。但是所有的檢查都應當使用斷言來完成。如果單元失敗了,你也能看到它,因為這個測試也會失敗。當測試通過時,什麼也不應當列印出來。在編寫測試**時,使用print語句有時是有用的。但是在需要用print的地方應當設定乙個標誌位,用來在進行測試的時候遮蔽它。

5. 檢視日誌資訊,而不是執行結果。還好這並不普遍,但是我卻見過乙個非常有能力的開發人員這麼幹過。要知道,真正重要的是方法的執行結果,而不是日誌中都列印了什麼,因為即使**中有錯誤,測試也可能會通過。好了,說的很明白了。

後面3個問題都很容易規避。頭2個問題則需要付出更多努力,但是會得到良好分離的**。

當我第一次聽說可以使用框架比如junit來進行單元測試的時候,我驚嘆這真是乙個簡單而強大的概念。它取代了隨機測試,使你可以儲存你的測試**,並按照需要隨時執行它們。按照我的理解,關於單元測試並沒有多少產生誤解的可能。但是過去的幾年中,我確實見過幾種或多或少不太正確的單元測試使用方式。這裡按照重要程度,列出5條:

1. 跟協作邏輯一起來測試演算法。如果跟協作邏輯**分離開來,那麼演算法邏輯是最容易測試的(參見選擇性單元測試 – 代價和好處)。否則在你的邏輯被測試之前,你就不得不先進行諸如通過任務佇列提交乙個任務之類的工作。 任務佇列部分只會使事情變得複雜。除非你想測試任務佇列本身,否則你就應當把呼叫run方法時所執行的邏輯剝離開來,並對它進行單獨測試。那樣,不論是編碼還是測試都會更易於編寫和管理。

2. mock測試太多。也許單元測試的最大好處就是它迫使你編寫能夠獨立測試的**。也就是說,你的**會變得模組化。當你把你要處理的物件的周圍的一切都模擬了,就沒有什麼能迫使你去把各部分分離開來。你會發現這樣寫出的**,你很難在外圍新增獨立的部分 – 因為所有東西都糾纏在一起。bill wake最近發推說: 」真是諷刺 – 模擬測試框架越強大,你在改進設計時所感受到的壓力就會越小。」

3. 不使用斷言。有時我會看到一些測試,裡面建立了乙個物件,呼叫了一些方法,然後,就沒有然後了。也許它是在迴圈裡這樣做的,而且在建立和呼叫上會有些差異。但是,卻沒有用斷言來做任何檢查。這就完全失去了意義 – 沒有檢查你的**是否按照預期進行工作的。當然,**是執行了,但是僅此而已。如果丟擲了乙個異常,我們會注意到它,但是卻不會驗證其它任何事情。

4. 在測試**中遺留print語句。我把這視為手工測試的後遺症 – 你希望看到物件的值來判斷它們是否正確。但是所有的檢查都應當使用斷言來完成。如果單元失敗了,你也能看到它,因為這個測試也會失敗。當測試通過時,什麼也不應當列印出來。在編寫測試**時,使用print語句有時是有用的。但是在需要用print的地方應當設定乙個標誌位,用來在進行測試的時候遮蔽它。

5. 檢視日誌資訊,而不是執行結果。還好這並不普遍,但是我卻見過乙個非常有能力的開發人員這麼幹過。要知道,真正重要的是方法的執行結果,而不是日誌中都列印了什麼,因為即使**中有錯誤,測試也可能會通過。好了,說的很明白了。

後面3個問題都很容易規避。頭2個問題則需要付出更多努力,但是會得到良好分離的**。

Grails 單元測試中的錯誤

在用grails寫乙個對service的單元測試的時候,test case失敗了,產生的錯誤是 no such property log for class articlecollectionservice groovy.lang.missingpropertyexception no such p...

tp5單元測試

暗夜在火星 發布於 2019 05 08 15 50 字數 1228 閱讀 516 收藏 2 點讚 0 phalapi thinkphp phpunit linux foundation開源軟體大學開源技術日直播首秀即將開始,聚焦5g aiot新藍海!在專案開發中,需要使用到thinkphp 5,為...

錯誤處理 邊界 單元測試

錯誤處理 使用異常而非返回碼 編寫可能丟擲異常的 時,先寫try catch finally語句 使用不可控異常 給出異常發生的環境說明,以便判斷錯誤的 和處所 依呼叫者需要定義異常類 打包呼叫api,確保返回通用異常型別,從而簡化 業務邏輯和錯誤處理 之間要有良好隔離 別返回null值,別傳遞nu...