C++單元測試

作者:gashero
鏈接:https://www.zhihu.com/question/27313846/answer/120164282
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

單元測試,或者更大一些的自動化測試,對提高軟件質量是有很大幫助的。通過一系列預先設計的規則,就可以覆蓋大量的測試點。尤其是對重構一類的任務,確保修改前後系統行爲不變很重要,而修改後的迴歸測試工作量又極其繁重,此時單元測試,或者自動化測試就能體現出無以倫比的效率。

我在2005年學Python不久,就鬱悶於自己那點代碼手工測試很麻煩,恰好那時得知了很多Python工程師有做單元測試的習慣,於是就學習了一下,果然效果卓羣。後來又經過數年整理出自己的一套單元測試的規範。

我做過的各類Python項目,代碼總量的50%左右是單元測試。經過這個級別的單元測試覆蓋,確保了底層函數基本不會出錯,這樣高層功能的調試才更方便。同時也是這個覆蓋程度確保了,被測試工程師發現bug的可能性已經很低了。

我給自己的單元測試設置了5個級別:

1. Level1:正常流程可用,即一個函數在輸入正確的參數時,會有正確的輸出
2. Level2:異常流程可拋出邏輯異常,即輸入參數有誤時,不能拋出系統異常,而是用自己定義的邏輯異常通知上層調用代碼其錯誤之處
3. Level3:極端情況和邊界數據可用,對輸入參數的邊界情況也要單獨測試,確保輸出是正確有效的
4. Level4:所有分支、循環的邏輯走通,不能有任何流程是測試不到的
5. Level5:輸出數據的所有字段驗證,對有複雜數據結構的輸出,確保每個字段都是正確的

如上的單元測試分級是我2007年整理出來的,後來在我做的各種項目中,一般只做到Level2,重要系統或者底層服務,要做到Level3或Level4。而很少做到Level5。即便如此,就已經實現瞭如上所說的,很難被測試工程師發現bug。

除了級別外,測試方法也要區分不同系統的玩法。比如基於WEB的系統,就需要確保單元測試裏可以模擬發送請求,這個一般是WEB框架提供支持的。比如我常用的web.py、Flask、Django都有支持。不僅僅可以模擬簡單的請求,還可以模擬POST、cookie等。另外一般建議單獨寫個函數來模擬登錄過程,這樣系統登錄後行爲的測試就不必反覆模擬登錄了。

單元測試一大痛苦是構造測試數據。我的看法是測試數據應該是人造的,而不是隨便從產品環境dump出來一份。只有人造的數據能確保環境可控,每次運行不會因爲環境改變而頻繁修改testcase。我的常用玩法是測試數據分爲基礎數據和附加數據兩部分。基礎數據是所有testcase共享的,比如建立幾個常用角色的用戶等等。附加數據是testcase內部自己建立的。這樣每次testcase運行時,先清空數據庫,導入基礎數據,導入附加數據,然後執行測試,驗證結果。

各類程序的函數可以分爲純函數和副作用函數。純函數對應的是數學裏函數的概念,輸出和輸入是一一對應的。對一個輸入有確定的輸出。比如1+1=2。而副作用函數則相反,同樣的輸入,在不同時間和環境裏,可能有不同的輸出。比如任何涉及IO、網絡、數據庫的。副作用函數的測試比純函數麻煩的多,因爲你必須要完整的構造其所依賴的所有環境,才能夠復現一個副作用函數的行爲。也正因爲如此,副作用函數出bug的概率比純函數高的多。理解這個概念以後,應該儘可能的把程序裏的純函數和副作用函數進行拆解,降低副作用函數的比例和邏輯複雜度。還有,副作用函數是會傳染的,一個函數如果調用了副作用函數,那麼它也會變成副作用函數。

肯定有人會給你推薦一些經典的單元測試框架,如GoogleTestcppunit 之類。

但我負責任的告訴你,那些框架太折騰了,你需要花很多時間和精力去學習使用,然後即使是一個非常非常小的項目,也要配置半天。

推薦給你一個新興的單元測試框架:Catch

它簡單到什麼程度?你只需要引入一個頭文件:

#include "catch.hpp"

另外,它因爲非常簡單輕巧,所以很容易學習,把這個簡短的教程看一遍,基本就掌握了。

爲了更直觀的瞭解這個框架,貼出教程上的一個例子:

#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

unsigned int Factorial( unsigned int number ) {
    return number <= 1 ? number : Factorial(number-1)*number;
}

TEST_CASE( "Factorials are computed", "[factorial]" ) {
    REQUIRE( Factorial(1) == 1 );
    REQUIRE( Factorial(2) == 2 );
    REQUIRE( Factorial(3) == 6 );
    REQUIRE( Factorial(10) == 3628800 );
}

這就是測試一個斐波那契函數的全過程。感覺如何?

vs2010 是沒有c++的單元測試模塊的, 只有.net的 , 所以vs2010幫助中,對單元測試的說明是跟調試的說明是一樣的,都是調試.。從這裏下載c++Test的插件版安裝。

使用VS2012內建的C++測試架構進行單元測試 http://blog.csdn.net/q_l_s/article/details/52190275


發佈了82 篇原創文章 · 獲贊 138 · 訪問量 79萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章