文獻標識碼: A
文章編號: 0258-7998(2014)12-0125-04
0 引言
隨著信息化軍事技術的不斷深入,嵌入式實時軟件已在工業控制、電子信息以及武器裝備等系統中發揮著越來越重要的作用;同時隨著嵌入式軟件的規模和復雜性的不斷提高,作為有效保證和驗證軟件質量的重要環節和依據,軟件測試已逐漸成為軟件研制成本最高的階段[1]。如何采用有效的嵌入式軟件工程化測試方法提高嵌入式軟件的質量和可靠性以及增強軟件組織自身的軟件測試能力具有極其重要的意義。
錯誤越早發現,項目付出的代價就越少,單元測試作為軟件項目中最早介入的測試活動[2],易于發現程序的錯誤和缺陷,也易于實現代碼測試的完全覆蓋,因此單元測試的好壞對于軟件質量的保證起著非常關鍵的作用。然而由于嵌入式軟件的特殊性,如實時性強、與硬件緊密相關、訪問硬件麻煩,在開發環境下模擬整個系統存在困難性,這使得測試一直是個難點,特別是單元測試,由于項目周期不允許,一些嵌入式軟件沒有進行單元測試或單元測試不徹底;有些嵌入式軟件代碼具有較高的耦合性,使單元測試難以進行;測試人員對于嵌入式軟件單元測試過于依賴自動化測試工具,使測試效果不能令人滿意,測試不規范,效率低[3],且無法確保嵌入式軟件單元測試的充分性和有效性。
針對上述問題,本文以集控嵌入式軟件為例,重點研究了基于Testbed軟件測試工具的靜態分析和動態測試方法,提出了一種較為完整和可操作的單元測試解決方法。研究分析了靜態分析輸出的度量模型值對嵌入式軟件的影響,并根據度量值提出了提高軟件代碼質量的措施;介紹了基于Tornado編譯環境的動態測試過程,并基于圈復雜度[4]提出了一種優先級的動態分析測試策略,以確保單元測試的充分性和有效性,提高軟件測試方法的效率和規范性,確保軟件的質量。
1 被測系統概述
被測系統集控軟件是一個實時嵌入式系統,運行在集控模塊控制單元內,控制單元由底板、CPU板和AD/DA板組成。板卡之間采用CPCI總線,通過CPU板上的兩路LAN接口與通信集控柜連接,完成與操舵臺、數采站、交流主配電柜、遙控操縱臺、綜控柜和顯控臺的網絡信息交換。CPU板上的一路RS422A接口與通信集控柜中的導航定位分機連接,完成導航定位信息的讀取;另一路RS422A接口與集控臺內手控模塊連接,完成指令的轉發和手控狀態的傳輸。控制單元中的AD/DA板與左/右主機齒輪箱執行器連接,完成速度調整。軟件的總體結構圖如圖1所示。
集控軟件使用C++/C語言編寫,程序基于模塊化思想設計,在實時多任務操作系統VxWorks上實現,基于Tornado的開發環境。按功能劃分模塊,采用多任務下的同步機制,通過消息實現各個模塊之間的通信。
在該軟件的單元測試中,采用靜態分析和動態測試相結合的方法來評估和完成軟件的充分性和測試的完備程度。
2 集控軟件測試關鍵步驟及實現
2.1 基于Tornado的仿真單元測試環境搭建
集控軟件單元測試工具采用的是Testbed,它是英國LDRA公司開發的一種軟件代碼測試及分析工具,主要用在軟件測試和軟件維護階段以便提高軟件產品的質量,該工具可提供編碼規則檢查、軟件度量分析、數據流分析、覆蓋率分析等功能[5]。在Testbed /Tbrun工具下配置集控嵌入式軟件的仿真單元測試環境,需滿足在Tornado2.2集成開發環境下成功編譯、執行測試驅動程序,具體步驟如下:
(1)借助Tbconfig工具完成Tornado2.2編譯環境的配置,并指定該開發環境的和測試工具的路徑;
(2)配置生成被測函數的驅動模板C:\LDRA_Toolsuite\
Vxworks 路徑下的vxworks_Cshlayout_663.dat,該模板用于生成被測函數的測試驅動;
(3)配置函數的插樁模板C:\Testbed760\Vxworks\Vxworks_
cinstr.dat,插樁模板的作用是對被測函數的入口、出口、控制流進行插樁,在單元測試結束時,用于分析單元測試的覆蓋率,以確定測試用例是否滿足覆蓋率需求。
2.2 集控實時嵌入式軟件的靜態分析
靜態分析是通過工具在非運行狀態下對程序結構、數據結構、代碼質量的分析,提取代碼大量的靜態內部信息,為代碼審查以及動態測試提供輔助參考的信息[5]。下面以集控軟件的網絡通信模塊UdpSocket.cpp為例,對其靜態測試過程和結果進行詳細說明。
2.2.1 靜態分析過程
運行測試工具Testbed,打開UdpSocket.cpp源程序,選擇MISRA編碼規則,然后在Select Analysis窗口下選擇分析菜單對該文件進行靜態分析,通過該項分析,為測試人員提供了該文件中各函數之間的調用關系模型,圖2幫助測試人員簡單明了地以顏色區分來顯示模塊間的調用關系,紅色為自定義函數,綠色為系統函數。圖3是UdpSocket.cpp中各子函數通過度量的比例分析數,可得出總函數的度量為91%,清晰性為 93%,可維護性為91%,測試性為100%。圖4是UdpSocket.cpp基于MaCabe的軟件度量模型對程序分析的Kiviat圖,每一軸代表一類度量元,被測試源代碼以扇形的結構顯示出來,綠色表示符合質量標準。圖5是UdpSocket.cpp基本節點數和基本圈復雜度數據分析柱狀圖。通過這些圖可以幫助測試人員了解代碼的靜態內部信息,發現缺陷。
2.2.2 靜態測試分析
靜態分析的結果能夠幫助測試人員從代碼內部結構信息中開展工作,幫助質量管理人員從軟件質量度量中進行質量監督[5]。通過對軟件靜態分析的總結,可以從降低代碼的圈復雜度和提高代碼的注釋率兩方面提高軟件代碼質量。
(1)降低代碼的圈復雜度
圈復雜度是應用最廣泛的靜態度量之一,用來衡量一個函數判定結構的復雜程度,圈復雜度公式V(G)=P+1,P是代碼中判定結點的數量[6]。程序的可能存在錯誤數和圈復雜度有著很大的相關性,圈復雜度越大代表程序代碼的質量低并且難以維護和測試[6]。
當代碼中遇到判定條件比較復雜時,可以將判定條件的表達式提前計算存儲在一個變量中,簡化判斷條件,減低代碼的圈復雜度,減少bug數。例如UdpSocket.cpp文件中有判定語句:
If ((UNIT)(szTemp[0] == 0xA5 && (UNIT)(szTemp[1]
== 0xA5) && (UNIT)(szTemp[2] == 0xA3))
{
}
該判定條件的判定結點為3,圈復雜度即為4,將代碼優化之后如下:
int num;
num=(UNIT)(szTemp[0] == 0xA5 && (UNIT)(szTemp[1] == 0xA5) && (UNIT)(szTemp[2] == 0xA3);
if (num)
{
}
優化后的代碼判定結點為1,圈復雜度為2。
(2)提高代碼的注釋率
提高代碼的注釋率可增加代碼的可讀性和可維護性,為每個代碼塊添加注釋,并在每一層使用統一的注釋方法和風格,包括每個類和每個方法。
2.3 集控實時嵌入式軟件的動態測試
2.3.1 測試用例設計
(1)測試用例數據的合理設計
測試用例的設計是為了提高測試代碼的覆蓋率,動態測試中最重要的過程是如何設計測試用例,著重測試數據的輸入設計。對于一般標準類型的輸入變量(如int、char、float、double等)并沒有多大問題,當變量是數組、指針、結構體、VxWorks中的FUNCPTR、LOCAL等特殊類型時,數據輸入就需要特別注意。當數組的下標值很大時,進行手工輸入是不可能的,可以在TBrun環境中有選擇地對需要的變量進行賦值或者在插樁后的代碼中插入數組的初始化語句對整個數組進行賦值;當變量是指針時,由于不能給指針直接賦地址,輸入指針采用映射的方法將指針變量映射成相應的自定義變量作為指針的輸入值;結構體變量賦值不正確時很容易導致測試用例跑飛掉,需要從源代碼找到該變量創建的賦值函數,將該函數作為變量的輸入值,必要時還需要添加函數的參數,例如本文需測試的文件CUdpSocket.cpp中有消息隊列數據結構體:
MSG_Q_ID msgId//接收消息的消息隊列ID號
其中MSG_Q_ID屬于VxWorks的系統調用,在文件中有對msgId的賦值語句:
msgId=msgQGreate()//創建消息隊列
在創建測試用例中對類型是MSG_Q_ID的變量輸入值應設為msgQGreate()。
(2)通過盡量少的測試用例達到盡量高的代碼覆蓋率。測試用例是以程序的內部結構為基礎來設計的,需要盡可能多地覆蓋程序的內部邏輯結構。
2.3.2 測試驅動的工作原理
動態測試過程中無法及時提供測試運行所需的真正目標機及其操作系統,必須正確配置開啟仿真模擬器并將其作為虛擬目標機,將Testbed經過編譯環境鏈接后生成的測試驅動程序下載到仿真模擬器中運行。每執行一個測試用例需要重新編譯和執行,函數的驅動程序是由Testbed/Tbrun根據驅動模板自動生成的,驅動程序是一個基于控制臺的程序,主要完成動態測試環境初始化,當調用測試用例時要執行函數ldra_qq_execute_test_
case_1(),該函數負責被測函數入口參數的初始化,然后再調用被測函數完成整個測試的過程。
2.3.3 采用圈復雜度優先級的動態測試策略
有效的測試策略可使軟件測試的效率最大化,從而滿足測試的各項要求并降低測試成本。由于基于Tornado開發環境的集控軟件代碼規模較大,功能模塊較多,結構復雜,因此為了提高測試效率,制定了一種基于優先級的動態測試策略,具體步驟如下:
(1)通過Testbed測試工具對每個文件靜態分析的結果從基本節點數和基本圈復雜度數據來分析柱狀圖,得到每一個文件中被測函數的圈復雜度和節點數。
(2)按圈復雜度進行高低排序,對圈復雜度高且重要的函數進行重點測試。圖5可看出UdpSocket.cpp文件中SocketSndData()函數的圈復雜度最高,因此首先對該函數進行重點測試。
(3)編譯鏈接通過之后,執行設計好的測試用例,用監控到的控制流信息來分析程序的覆蓋率,依據分析結果不斷補充和優化測試用例。根據各模塊的語句和分支覆蓋率、已執行語句、執行路徑以及未執行的語句,判定覆蓋率并衡量是否完成動態測試活動。圖6為UdpSocket.cpp文件中SocketSndData()函數的動態測試圖,圖右上角可以得到該函數的語句分支覆蓋率都為100%,圖左下角是設計并執行通過的測試用例,右下角是用例數據的設計輸入。
3 結論
(1)圖形界面框架類單元測試問題:由于Testbed工具自動生成的測試驅動入口是main()函數,類似于控制臺程序,當遇到圖形框架環境時無法完成測試。框架類(例如MFC,NI)應用程序的執行是以事件驅動面向對象的結構,定義了很多的API,應用程序可以直接調用。兩種結構是完全不同的,當直接使用測試工具生成測試驅動時,由于缺少庫文件,編譯不能通過,無法執行測試用例進行測試。
(2)被測單元代碼的必要修改:雖然大多數編譯環境和Testbed工具關聯在一起,但有一些代碼單元還是不能直接執行測試,代碼在動態測試之前必須做適當的修改,比如一些中斷函數、死循環while()以及Forever等。
(3)測試人員不能過于依賴測試工具:自動化靜態分析存在一定的機械性,測試人員需逐項進行分析確認出真正的問題所在,有效的測試不能簡單的依靠測試工具。
參考文獻
[1] 丁旭,崔吉崗,劉春裕.軍用嵌入式軟件結構覆蓋測試技術[J].指揮控制與仿真,2008,30(3):120-122.
[2] 李金麒,徐建平.嵌入式系統軟件可靠性設計與測試方法[J].計算機系統應用,2013,22(1):74-78.
[3] 肖波.通訊系統嵌入式平臺下的單元測試技術研究[D].上海:華東師范大學,2005.
[4] 孫夢磷,宋曉秋,巢翌.軟件程序代碼質量度量技術研究[J].計算機工程與設計,2006,27(2):325-327.
[5] 張大林.基于缺陷關聯的靜態分析優化[J].軟件學報,2014,25(2):386-399.
[6] 陽凡林,康志忠.基于多維度覆蓋率的軟件測試動態評價方法[J].軟件學報,2008,21(9):2135-2146.