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