欒家偉 吳 陳
(江蘇科技大學 鎮(zhèn)江 212003)
隨著軟件行業(yè)的蓬勃發(fā)展,軟件的逐漸規(guī)范化以及軟件規(guī)模的日益遞增,不僅僅表面上繁重軟件開發(fā)工作,規(guī)模遞增的軟件也意味著有著大量的軟件測試工作,甚至往往軟件測試工作占據(jù)一半以上的軟件開發(fā)周期。所以面對巨大的軟件測試工作量必須提高測試效率,減少開發(fā)周期降低開發(fā)成本,并且能夠同時完成測試目標提高軟件質(zhì)量。
面向?qū)ο蟮慕y(tǒng)一建模語言UML主要由圖形、模型元素、視圖以及通用機制組成。主要用于描述軟件規(guī)格、可視化研究、軟件系統(tǒng)的建模與分析。UML可以針對不同的軟件開發(fā)方法,貫穿軟件生命周期的各個階段。UML通常用來描述對象、子系統(tǒng)、系統(tǒng)的狀態(tài)遷移關系。描述面向?qū)ο箢惖哪骋粚ο笳麄€生存周期的具體行為。直觀地給出了特定對象可能進入的所有狀態(tài),以及該對象的狀態(tài)如何影響該對象的事件。
本文選取UML圖形中的狀態(tài)圖用以研究如何基于UML實現(xiàn)測試用例的自動生成。狀態(tài)圖主要是由狀態(tài)和變遷組成的圖,包括事件、狀態(tài)、變遷三個部分。UML狀態(tài)圖是UML中對系統(tǒng)的動態(tài)行為進行建模的表示方法,它包括對反應型對象的行為建模。UML狀態(tài)圖能夠直觀地給出了特定對象可能進入的所有狀態(tài)和觸發(fā)狀態(tài)轉(zhuǎn)移的條件,以及對象的動作行為,通常表現(xiàn)為狀態(tài)所經(jīng)歷的狀態(tài)序列,也包含引起狀態(tài)轉(zhuǎn)移的事件,以及狀態(tài)轉(zhuǎn)移伴隨的動作,它可以對一個對象的生命周期建模[1]。UML狀態(tài)圖其實就是代表一個狀態(tài)機,刻畫描述對象狀態(tài)變遷。
J.Offutt等曾經(jīng)提出關于UML狀態(tài)圖主要有四個測試覆蓋準則:狀態(tài)覆蓋準則、狀態(tài)變遷覆蓋準則、狀態(tài)變遷對覆蓋準則、全序列覆蓋準則。并開發(fā)了一個驗證性的測試用例生成工具UMLTest實現(xiàn)了對Rational Rose模型文件的解析,從而讀出狀態(tài)圖模型,然后利用相應的測試準則來產(chǎn)生測試用例[2]。
基于UML模型生成軟件測試主要是對軟件系統(tǒng)進行UML建模,根據(jù)需求規(guī)格說明所建立的UML模型的狀態(tài)圖,提取對應信息將其轉(zhuǎn)化為有向圖,用深度優(yōu)先算法對有向圖進行遍歷得到相應的測試用例。
路徑覆蓋:在白盒測試中,路徑覆蓋能夠滿足設計出足夠多的測試用例,覆蓋程序中所有可能的路徑以達到覆蓋度最高。但是當程序過于復雜,判斷和循環(huán)過多時,實現(xiàn)路徑的完全覆蓋卻幾乎是不可能的。程序中的路徑數(shù)(復雜度)通過公式V(G)=e-n+2得到(e為邊數(shù),n為節(jié)點數(shù))。
深度優(yōu)先算法思想從圖的頂點V出發(fā),訪問V的未被訪問鄰接點V',再從V'出發(fā),繼續(xù)訪問未被訪問的鄰接點,直至一個不存在未被訪問鄰接點的某節(jié)點,此時返回上一個存在未被訪問鄰接點的節(jié)點,當所有節(jié)點的鄰接點都處于已被訪問狀態(tài),結(jié)束遍歷。路徑覆蓋策略實現(xiàn)過程如圖1。
圖1 路徑覆蓋策略
利用深度優(yōu)先算法對有向圖進行遍歷從而實現(xiàn)路徑覆蓋的目的。從圖的開始節(jié)點進行遍歷,一直到路徑的結(jié)尾,遇到分支即進行拷貝,用二維數(shù)組event[rows][0]存儲事件集合,path[rows][1]存儲路徑集合,當path是完整路徑時結(jié)束遍歷循環(huán)。
不過在開始路徑尋找之前,首先判斷是否有分支
Isbranch(s,n,i){
If(s[i].start==s[num].start&&s[i].end!=s[num].end);
}
如果存在分支的話,還需要進行起始節(jié)點和分支節(jié)點的判斷,如果該節(jié)點為起始節(jié)點,則進行下面的處理:
If(s[i].start==“start”){
event[rows][0]=s[i].sevent+“”;
path[rows][1]=s[i].start+“->”+s[i].end;
}
如果判斷為該節(jié)點為分支節(jié)點,則如下處理:
event[rows][0]=event[rows][0]+s[i].sevent+“”;
path[rows][1]=path[rows][1]+“->”+s[i].end;
在采用語句覆蓋策略時,先通過貪心算法對進行第一次遍歷,每個節(jié)點只遍歷一次。如果節(jié)點為聚合節(jié)點或者分支節(jié)點的特殊情況下,可能會出現(xiàn)節(jié)點遍歷遺漏的情況,這種情況下基于回溯法的思想,采用雙向回溯,實現(xiàn)回溯功能。
對節(jié)點的上下遍歷過程進行檢查,如果該節(jié)點存在下一個未遍歷過程則返回該節(jié)點在數(shù)組中的下標,則進行如下的處理:
isnext=Istrackingnext(s,n,finals);//測試是否存在下一個
未訪問過的節(jié)點
intIstrackingnext(Swant s[],int n,String finals){
for(int j=0;j<n;j++){
if(s[j].state==1&&s[j].start==finals)
return j;
}}
當只存在下節(jié)點未遍歷時,對下節(jié)點進行遍歷,然后將結(jié)束節(jié)點標記置為下節(jié)點的結(jié)尾,并將下結(jié)點設置為已遍歷訪問。
If(isnext=!-1&&ispre==-1)//當只存在下節(jié)點時操作
{
getnxtevent=s [isnext].DateOfConditionOrPredicateAnd?Condition(s[isnext].sevent);
event[rows][0]=event[rows][0]+“”+getnxtdate[1];
path[rows][1]=path[rows][1]+“->”+s[isnext].end;
finals=s[isnext].end;//將結(jié)束節(jié)點標記置為下節(jié)點的末尾
s[isnext].state=0;//下節(jié)點置已訪問標記
}
如果該節(jié)點存在上一個未遍歷的過程則進行如下處理:
ispre=Istrackingpre(s,n,begin);//測試是否存在上一個未訪問過的節(jié)點
int Istrackingpre(Swant s[],int n,String begin){
for(int j=0;j<n;j++){
if(s[j].state==1&&s[j].end==begin)
return j;
}}
當存在上節(jié)點未遍歷時,對上節(jié)點進行遍歷,然后將開始節(jié)點標記置為上節(jié)點的開頭,并將上節(jié)點設置為已遍歷訪問。
If(isnext==-1&&ispre!=-1)//當只存在上節(jié)點時操作
{
getpreevent=s [ispre].DateOfConditionOrPredicateAnd?Condition(s[ispre].sevent);
event[rows][0]=getpreevent[1]+“ ”+event[rows][0];
path[rows][1]=s[ispre].start+“->”+path[rows][1];
begin=s[ispre].start;//將開始節(jié)點標記置為上節(jié)點的開頭
s[ispre].start=0;//上節(jié)點置已訪問標記
}
如果上下節(jié)點都存在未訪問的情況,將開始節(jié)點標記設置為上節(jié)點的開頭,結(jié)束節(jié)點標記設置為下節(jié)點的末尾,并將上下節(jié)點設置為已遍歷訪問。
if(isnext!=-1&&ispre!=-1)//上下節(jié)點都存在時進行的操作
{
getpreevent=s [ispre].DateOfConditionOrPredicateAnd?Condition(s[ispre].sevent);
getnxtevent=s [isnext].DateOfConditionOrPredicateAnd?Condition(s[isnext].sevent);
event[rows][0]=getpreevent[1]+“”+event[rows][0]+“”+getnxtevent[1];
path[rows][1]=s[ispre].start+“->”+path[rows][1]+“->”+s[isnext].end;
begin=s[ispre].start;//將開始節(jié)點標記置為上節(jié)點的開頭
finals=s[isnext].end;//將結(jié)束節(jié)點標記置為下節(jié)點的末尾
s[ispre].state=0;//上節(jié)點置已訪問標記
s[isnext].state=0;//下節(jié)點置已訪問標記}
軟件測試是為了發(fā)現(xiàn)軟件開發(fā)的錯誤,測試用例的自動生成對于整個軟件開發(fā)的效率和軟件質(zhì)量有著巨大的促進作用。UML狀態(tài)圖能夠通過描述對象的狀態(tài)變化,提供對象在整個生命周期中的詳細狀態(tài)信息。本文研究了基于UML狀態(tài)圖實現(xiàn)測試用例的生成,主要介紹了兩種生成策略,將白盒測試技術(shù)中的路徑覆蓋以及語句覆蓋和UML狀態(tài)圖相結(jié)合,以此實現(xiàn)測試用例的自動生成。今后可能還會嘗試基于UML中其他如類圖,活動圖等實現(xiàn)測試用例的生成進行更多研究探討。