曾經看過一篇介紹某靜態測試工具的文章,說該工具可以發現所有的代碼錯誤,我覺得很好奇,問:如果我寫了一個加法函數,把加號寫成減號,如int add(int a, int b){return a-b;};,可以找出來嗎?答:這是代碼功能錯誤,當然不能找出來。愣了半天,沒想明白:難道代碼的功能錯誤不是代碼錯誤?怪偶語文沒學好,理解不了這種高深的文字游戲。
靜態測試方法到底可以發現哪些錯誤?極限是什么?這要從數據和代碼的自然屬性和業務屬性說起。
數據具有自然屬性,如一個無符號32位整數,具有最大、最小值,正負數交界處如0、1、-1比較特殊,不能被零除等。這些自然屬性,無論在什么代碼中都是一樣的。程序中的數據通常還具有業務屬性,如一個無符號32位整數,在這個代碼中可能表示一個人的年齡,有效值為0-200,在另一個代碼中可能表示星期幾,有效值為0-6。程序要對業務屬性做出合適處理,如年齡小于1的為嬰兒,要特殊照顧;或者星期一至五要工作,周末要休息。數據的自然屬性很少,基本類型就那么幾種,高級類型都是基本數型的組合。數據的業務屬性則是千變萬化無窮無盡的。數據的自然屬性是死的,在什么代碼中都一樣;數據的業務屬性是活的,要根據需求來確定。
代碼也具有自然屬性,如要符合語法規范、數組不能越界、條件語句中含有“=”則可能是“==” 的誤寫等等。代碼更具有業務屬性,也就是要實現需要的業務功能,否則寫得像花一樣也沒有意義。相對于業務屬性,代碼的自然屬性也是很少的,并且同一語言的代碼屬性是基本不變的,不管代碼用來做什么,自然屬性都差不多。代碼的業務屬性則是千變萬化無窮無盡的,并且要符合設計需求。
代碼的錯誤有可能來自自然屬性,也可能來自業務屬性。由于數據和代碼的自然屬性是簡單且有限的,而業務屬性則是復雜且無窮的,因此,來自業務屬性錯誤遠遠高于來自自然屬性的錯誤。
靜態測試方法通過分析代碼來發現錯誤,所依據的只能是數據和代碼的自然屬性,對業務屬性則一無所知。這就是這類方法的極限,也就是說,靜態測試方法做到極致,也只能發現一小部分錯誤。另外,靜態分析只能基于現有代碼,也不能發現代碼缺失造成的錯誤。我看過一些靜態測試的示例,基本上都是使用排序算法之類的小程序,這是一個巧妙的選擇,因為這類程序中,數據只有自然屬性,例如大小之分,沒有業務屬性?上У氖,除非你正在編寫通用底層庫,否則多數代碼和數據都是具有業務屬性的。
要發現多數錯誤必須用動態測試方法,并且測試數據要人工設計,因為,只有人才能理解代碼的功能,才能既了解代碼和數據的自然屬性,也了解業務屬性。
靜態方法和動態方法所發現的錯誤并不是互補關系,而是包含關系。人工設計用例時,既會考慮數據和代碼的自然屬性,也會考慮其業務屬性,因此,動態方法既能發現來自自然屬性的錯誤,也能發現來自業務屬性的錯誤。實際上,自然屬性引起的錯誤也會以功能錯誤的方式表現出來,例如,除零錯誤、數據越界會引起崩潰,當然也是功能錯誤;if(a==0)寫成if(a=0)也不能實現正確功能,并且會造成else分支不可覆蓋。
靜態方法通常是自動的,但只是掃描過程自動,其輸出通常存在大量的漏報和誤報。漏報我們不說它,如果能直接報告一兩個明確的錯誤,那也不錯,畢竟是自動的,但誤報則是大問題,大量的誤報導致需要大量的后續人工分析,并可能掩蓋真實的錯誤,從這一點來說,并不自動。
最方便高效的靜態分析工具是編譯器。百度說誰最懂中文?當然是中國人最懂中文。那么誰最懂代碼?編譯器最懂代碼。編譯警告就是很好的靜態分析信息,例如,VC6的編譯警告有四級,默認為三級,如果設為四級,你會發現這個十多年前的老工具,其報告潛在錯誤的能力不遜于一些現代的專門靜態測試工具。
靜態測試方法當然有它的價值,但并沒有那么神奇。如果你要評估靜態測試的效果,那么要考慮其他條件,例如做不做動態測試、編譯器的報錯功能是否已發揮?如果不做動態測試,那么靜態分析并不能發現大多數錯誤,如果要做,靜態測試則基本沒有意義。我說的也許是錯的,最好自己評估一下:如果是在要做動態測試的前提下評估,那么要先做動態測試,再評估靜態測試;如果是在不做動態測試的前提下評估,那么,把編譯器的警告級別提至最高,先解決警告問題,再評估靜態測試,只有這樣,才能真正判斷測試測試的價值。
文章來源于領測軟件測試網 http://www.kjueaiud.com/