概述
在實現覆蓋測試的過程中,往往需要知道某些信息,如:程式中可執行語句被執行(即被覆蓋)的情況,程式執行的路徑,變數的引用、定義等。要想獲取這類信息,需要跟蹤被測程式的執行過程,或者是由計算機在被測程式執行的過程中自動記錄。前者需要人工進行,效率低下且枯燥乏味;後者則需要在被測程式中插入完成相應工作的代碼,即代碼插樁技術。如今大多數的覆蓋測試工具均採用代碼插樁技術。 在對普通套用的軟體進行測試時,由於現在電腦的配置越來越高,電腦的運行速度越來越快,代碼插樁所引起的問題還不是很明顯或者說是在可以接受的範圍之內。但是對於嵌入式軟體來說這卻是致命的問題。因為嵌入式軟體的系統資源有限(記憶體較小、i/o 通道較少等),過大的代碼膨脹率將使得程式不能在嵌入式系統中運行;同時嵌入式軟體通常具有很強的實時性,程式的輸出只在有限的時間內有效,遲到的“正確的”結果是無用的甚至會變成錯誤的、有害的。 代碼插樁技術會破壞程式的時間特性等,導致軟體執行的錯誤。因此我們需要更高效的代碼插樁技術來完成覆蓋測試,尤其是嵌入式軟體的覆蓋測試。
方式比較
由於程式插樁技術是在被測程式中插入探針,然後通過探針的執行來獲得程式的控制流和數據流信息,以此來實現測試的目的。因此,根據探針插入的時間可以分為目標代碼插樁和原始碼插樁。 (1)目標代碼插樁的前提是對目標代碼進行必要的分析以確定需要插樁的地點和內容。由於目標代碼的格式主要和作業系統相關,和具體的程式語言及版本無關,所以得到了廣泛的套用,尤其是在需要對記憶體進行監控的軟體中。但是由於目標代碼中語法、語義信息不完整,而插樁技術需要對代碼詞法語法的分析有較高的要求,故在覆蓋測試工具中多採用原始碼插樁。 (2)原始碼插樁是在對源檔案進行完整的詞法分析和語法分析的基礎上進行的,這就保證對源檔案的插樁能夠達到很高的準確度和針對性。但是原始碼插樁需要接觸到原始碼,使得工作量較大,而且隨著編碼語言和版本的不同需要做一定的修改。在後面我們所提到的程式插樁均指原始碼插樁。
設計
(1)插樁位置: 探針的植入要做到緊湊精幹,才能保證在做到收集的信息全面而無冗餘,減少代碼的膨脹率。因此,在確定插樁位置時,要將程式劃分,基本的劃分方法是基於“塊”結構。 按照塊結構的劃分,探針的植入位置有以下幾種情況: a. 程式的第一條語句;b. 分支語句的開始;c. 循環語句的開始;d. 下一個入口語句之前的語句;e. 程式的結束語句;f. 分支語句的結束;g. 循環語句的結束;除此之外,根據覆蓋測試要求的不同,插樁的位置除了上面所說的幾種情況外,也會隨著覆蓋測試要求的不同有所變化。 (2)插樁策略: 插樁策略是解決“如何插”的問題。傳統的插樁策略是在所有需要插樁的位置插入探針,在程式運行過程收集所有可能用到得程式信息,將其寫入資料庫進行分析和處理。這種方法對於大型的程式來說,將會造成相當大的工作量,效率很低,且會造成很大的代碼膨脹率。而我們會根據不同的測試要求,每次插入不同的探針,採用相應的插樁策略,這樣就減少了代碼的膨脹率,保證了程式執行的效率。下面簡單介紹幾種探針的插樁策略。 語句覆蓋探針(基本塊探針):在基本塊的入口和出口處,分別植入相應的探針,以確定程式執行時該基本塊是否被覆蓋。 分支覆蓋探針:c/c++語言中,分支由分支點確定。對於每個分支,在其開始處植入一個相應的探針,以確定程式執行時該分支是否被覆蓋。 條件覆蓋探針:c/c++語言中,if, swich,while, do-while, for 幾種語法結構都支持條件判定,在每個條件表達式的布爾表達式處植入探針,進行變數跟蹤取值,以確定其被覆蓋情況。 根據不同測試要求採用不用的插樁策略,每次在不同的位置植入相應的探針,使得每次只是植入有限的探針,這就更大大減少了代碼的膨脹率和插樁的速度。
實驗
採用了一個 1000 行的程式作為被測程式,分別採用使用整體插樁的工具和我們自己開發的工具進行測試,結果發現前者插樁的時間和代碼膨脹率分別為3s 和35%,後者插樁的平均時間和平均的代碼膨脹率為1s 和8%,插樁時間得到明顯提升,代碼膨脹率明顯減少。 採用以上的程式插樁技術,除了常用的覆蓋測試策略外,我們還可以實現mc/dc 和lcsaj 測試。