嵌入式軟件測試淺談
嵌入式軟件測試與普通軟件測試的目的一樣,都是為了發現軟件缺陷,而后修正缺陷以提高軟件的可靠性。嵌入式系統安全性的失效可能會導致災難性后果,即使非安全性失效,由于其應用場合特殊也會導致重大經濟損失。因此,往往嵌入式軟件對可靠性的要求比普通軟件高。這就要求對嵌入式軟件進行嚴格的測試、確認和驗證,以提高產品的可靠性。
不過由于嵌入式軟件的多樣性,基于的操作系統,使用的開發環境,微控制器都是日益繁多,完整規范的測試實現起來比較困難,一般企業都是直接進行系統測試。單元測試,集成測試由于測試執行的運行環境建立困難,執行效率低下,或者維護困難就往往被忽略。
實際上,只要時間上做好安排,確立測試方案,根據情況建立單元測試環境,還是可以順利實施單元測試,盡早發現軟件缺陷,整體上獲得時效,提高了系統可靠性。文中筆者就根據多年工作實踐,將嵌入式軟件單元測試相關的一些經驗與大家分享,同時拋磚引玉。
測試環境
單元測試首先需要動態運行代碼的環境,嵌入式軟件開發環境往往是交叉開發環境,我們希望將代碼移植到開發主機上運行(比如Windows系統),這樣做有幾個好處:
1 可以利用高速的主機提高代碼運行效率;
2 有利于測試管理,便于測試用例輸入和形成測試結果報表和維護;
3 充分利用Windows系統的測試工具,實現自動化測試。
不過移植代碼至Windows系統需要將嵌入式軟件的API都移植到Windows,形成虛擬系統接口層,這種方法往往是長期使用這一嵌入式系統,一勞永逸的長遠性方案。
當然還可以通過購買使用一些商用的工具,比如CodeTest,VcTester,使用這些工具在嵌入式系統上直接開展單元測試工作。
這兩種方案對于一些中小企業來說,由于不愿投入這么大人力物力,不能建立長期有效的開發方案而無法實施。對于這種條件還可以采用一種投入較小的短時方案,直接在程序中加入測試代碼,直接在目標板上運行查看結果,測試用例也可以直接在代碼中,或者通過接口從主機獲得測試輸入及輸出測試結果。這一方案對于測試硬件驅動也是相當適用的,比如測試某設備讀寫做了以下c語言代碼(詳見本刊網站):
在實際平臺上運行該代碼執行測試,這種方法主要用于單元的功能測試。雖然需要在單元測試階段編寫額外的代碼,但是由上面例子可見,被測單元接口定義清晰,測試代碼很容易完成,至于測試用例的編寫是無法避免的。正式發布代碼時通過條件編譯將這些代碼屏蔽即可。
測試策略
從測試效果上看,當然是花費越多的時間、人力,發現的問題越多,產品的質量控制得更好。但實際上,徹底做好軟件單元測試幾乎是不可能的,我們需要綜合考慮成本和效率,這是實際產品開發中經常遇到的問題,都面對這樣兩難的境地——上市時間延誤而沒有及時占領市場;或是時間上搶先,不過測試不充分導致出廠的產品質量不高。如果測試時間不充足,如何在限定時間內更好地完成測試工作呢?
1 我們需要強調對隱藏缺陷多的模塊進行測試:問題是怎么在測試計劃之前確定哪些模塊缺陷多,容易出錯呢?根據經驗,出錯率大的地方往往是以下幾種情況:
1)時間壓力大的情況下完成的模塊;
2)經驗不足的員工編寫的模塊;
3)前期發現過大量bug的模塊;
4)接口關系復雜的模塊;
5)技術難度大,處于行業領先地位的模塊;
6)從未做過測試或缺乏底層測試的模塊。
2 對于重要的模塊加強測試:“重要”這個概念在這里往往也不是輕易評估的,實際實施中應該需要測試評審小組商議決定。這里就根據經驗列出以下幾點作為參考:
1)和安全相關的模塊,比如產生輻射,高溫,高壓等威脅人身安全的模塊,這是最為關鍵的一點;
2)從經濟利益角度考慮,出現故障將造成較大經濟損失的模塊;
3)從使用角度看,用戶操作的模塊優先級要高于服務操作模塊,因為用戶的優先級高于客服人員;
4)基本功能模塊優先級高于擴展功能模塊,試想基本功能都不能使用,那擴展功能豈不是空中樓閣;
5)執行概率高的模塊,因為執行概率高的代碼在運行中暴露缺陷的幾率也大。
編碼注意事項
以上是從測試角度討論如何建立單元測試執行環境的幾種方案和測試策略的制定,不過,為單元測試的實施奠定堅實的基礎的還是良好的程序設計。接下來從代碼編寫角度列舉提高嵌入式軟件的可測性的幾點經驗教訓:
1 與硬件設備操作相關的需要與硬件操作無關的代碼分離,這樣與硬件操作相關的驅動代碼可以獨立在目標板上測試,當然邏輯簡單也可不作測試;大部分與硬件操作無關的代碼就容易實現跨平臺移植測試。
2 中斷響應函數功能盡量簡單,這是因為中斷響應相對不好測試,如果代碼復雜,也不易定位錯誤,因為很多的開發環境或操作系統難以支持中斷響應函數的斷點調試。
3 系統調用及操作系統相關的操作做到與應用層分離,可以通過中間函數實現,比如虛擬操作系統函數,這樣跨平臺移植測試的時候只需將這些中間層函數修改就可以實現。
4對數據類型的差異性也可通過宏定義來實現統一,對于庫文件的差異也通過宏定義來實現上層代碼的一致性。
5 使用靜態代碼檢測工具,比如PC-Lint,以盡早發現代碼缺陷。PC-Lint是在代碼產生初期靜態查找代碼缺陷,更有利用錯誤定位和修改,因為軟件開發階段越早發現問題,解決問題花費的代價越小。因此,一般應該是靜態檢查通過后再實施動態測試。
嵌入式軟件單元測試也是基于普通軟件單元測試的理論,仍需遵守,以上是對嵌入式軟件單元測試特別之處的經驗總結,希望能對初涉嵌入式軟件開發的朋友有所幫助,重視軟件質量,提高嵌入式系統的可靠性。
- {
- typedef struct _TEST_CASE // 測試用例結構體
- {
- UINT8* pBuf; //讀寫緩沖區指針
- int len; //讀寫數據長度
- STATUS result; // 測試結果,OK或ERROR
- } TESTCASE;
- #define TEST_NUM 4 // 測試用例數
- UINT8* rBuf;
- TESTCASE testCase[TEST_NUM]={
- {0,DATA_MAX_LEN+1,ERROR}, // DATA_MAX_LEN指允許讀寫的***長度
- {"a",1,OK},
- {"12",2,OK},
- {0,DATA_MAX_LEN,OK}
- };
- for (int i=0;i< TEST_NUM;i++)
- {
- if(write(testCase[i].pBuf,testCase[i].len) != testCase[i].result) // 寫測試
- LOG ("test write failed!");
- if(read(rBuf,testCase[i].len) != testCase[i].result) // 讀測試
- LOG ("test read failed! ");
- if(bcmp(testCase[i].pBuf,rBuf,testCase[i].len) != 0) // 比較讀寫數據
- LOG ("compare data failed! ");
- }
- }
其實大多數軟件測試方法都可以直接或間接地用于嵌入式軟件的測試,但是由于操作系統的實時和嵌入式特性,嵌入式軟件測試也面臨一些特殊的問題。雖然日前已經有一些針對嵌入式軟件的測試和調試工具,但是在有些方面仍存在不足,包括許多任務操作系統的并發、非侵入式的測試和凋試、嵌入式系統的軟件抽象等。對于嵌入式軟件測試技術的研究人選測試工具有待開發,仍須要做很多進一步的工作。
【編輯推薦】