基於XML和Python實現白盒測試程式與測試用例分離
【摘要】進行白盒測試時,或者將測試用例和測試程式混在一起難以閱讀;或者花很大精力構思用例的格式,然後編寫較複雜的程式進行用例的提取;本文提出一種XML用例編寫規範和解析思路,它基於python的XML解析器minidom,可以快速完成測試用例與測試程式分離。
鑑於XML在資料傳輸上的優越性,無論基於何種語言而開發的專案,採用基於XML進行用例編寫,都將在通用性、相容性和程式易編性上收穫頗豐。
【關鍵詞】白盒測試;XML;Python
Python的 XML解析器
終端UI採用了跨平臺語言Python進行開發,保證了一套UI可以不用修改即可在眾多主流作業系統上使用;採用python的解析器
Python25/ Python2.5 安裝根目錄 (可執行檔案的所在地)
|
+--lib/ 庫目錄 (標準庫模組的所在地)
|
+-- xml/ xml包 (實際上目錄中還有其它東西)
|
+--sax/ xml.sax包 (也只是一個目錄)
|
+--dom/ xml.dom包 (包含 minidom.py)
|
+--parsers/ xml.parsers包 (內部使用)
Python
from xml.dom import minidom
xmldoc = minidom.parse('pbkTestCase.xml')
第一句話匯入我們的minidom模組,第二句話將指定的XML檔案使用parse方法解析之,這是將整個XML文件一起讀取解析的。從 minidom.parse 返回的物件是一個 Document 物件,它是 Node 類的一個子物件。這個Document 物件是連鎖的 Python 物件的一個複雜樹狀結構的根層次,這些 Python 物件完整表示了傳給 minidom.parse 的 XML 文件。每個 Node 都有一個 childNodes
XML測試用例格式約定
XML測試用例格式有如下三條約定:
(1) 以<function>和</function>作為一個測試函式的起始和結束標誌;
(2) 以<ref>和</ref>作為一個測試用例的起始和結束標誌;
(3) 以<p>和</p>作為一個測試用例的引數的起始和結束標誌;
每個測試文字包含眾多的 ”function” ;每個 ”function” 包含眾多的 ”ref” ;每個 ”ref”包含眾多的”p”。這樣的XML文字便包含了眾多的節點和子節點,採用上節提到的childNodes屬性可以很容易的找到各個節點;3層結構使整個用例看起來比較明晰,而且每層使用統一的識別符號,簡化了解析程式的編寫。一個完整的例子如下:
<?xml version="1.0"?>
<!DOCTYPE phonebook>
<phonebook>
<function id="test_CreatCategories">
<ref id="1">
<p> Mn*$</p>
<p>AppGlobals.TpvSimPbPC</p>
</ref>
<ref id="2">
<p>#12Ab&%</p>
<p>AppGlobals.TpvSimPbSIM</p>
</ref>
</function>
</phonebook>
上面是一個名片夾建立群組的兩個用例,一個在PC側建立名稱為”Mn*$”的群組,另外一個是在SIM卡上建立名為”#12Ab&%”的群組。每個函式都有唯一的ID,便於解析程式提取此函式,ID的值不侷限於數字,我們是將ID賦成每個測試函式的名字,這樣解析程式將其作為字典的鍵,可以很明顯的與測試函式對應,便於維護用例和程式。
測試用例的解析
上述測試用例的編寫規則給解析用例帶來了很大的便利。由於每個函式、每條用例及引數的標誌固定,根據不同的ID即可將所需要的資料提取出來。解析過程如下:
(1) 通過getElementsByTagName屬性找到每個測試函式;
(2) 使用attributes[u"id"].value,通過不同的ID,得到測試函式名,作為儲存測試用例的字典的‘鍵’;
(3) 通過getElementsByTagName屬性找到測試用例和用例引數,將其存入列表後,作為測試函式‘鍵’對應的‘值’存入字典;
(4) 新增一定的判斷邏輯,給編寫測試用例提供一些方便,比如測試用例的引數過長時,進行換行等。
下面是解析過程的python程式描述:
def importFile(path):
funcTC = {} #定義一個字典,用來儲存測試用例的鍵-值
xmldoc = minidom.parse(path) #解析path路徑下的某XML檔案
funcList = xmldoc.getElementsByTagName_r(u'function')
for i in range(len(funcList)):
#根據不同的ID,得到每個測試函式的函式名
funcName = funcList[i].attributes[u"id"].value
#根據不同的ref和p,得到每個測試函式對應的測試用例其用例引數
refList = funcList[i].getElementsByTagName_r(u'ref')
refTC = [] # 測試用例儲存到列表中
for j in range(len(refList)):
pList = refList[j].getElementsByTagName_r(u'p')
pTC = []# 測試用例的引數也儲存到列表中
for k in range(len(pList)):
# 對用例引數的換行輸入進行識別
temp1 = pList[k].firstChild.data.split(u'/n')
for w in range(len(temp1)):
# 對用例引數的空格和tab鍵進行識別
temp1[w]=temp1[w].strip(u'/t').strip()
temp2 = ''
for q in range(len(temp1)):
temp2 += temp1[q]
pTC.append(temp2)
refTC.append(pTC)
funcTC[funcName] = refTC # 測試用例存入字典中
return funcTC #返回我們從XML中提取的有效的測試用例資料
以我們上述建立群組的用例說明,我們的解析程式返回的資料如下:
funcTC={u'test_CreatCategories':[[u'Mn*$',u'AppGlobals.TpvSimPbPC'],[u'#12Ab&%', u'AppGlobals.TpvSimPbSIM']]}
測試用例在測試程式中的使用
由於有效的測試用例已經在字典中儲存,測試程式可以非常方便的使用字典的鍵-值來獲取需要的資料。測試程式只需要進行以下幾步即可獲取需要的資料:
from allTestCaseXml import importFile
pbkTestCase=importFile("./pbkTestCase.xml")
for i in range(len(pbkTestCase['test_CreatCategories'])):
[groupName,Flag]=pbkTestCase['test_CreatCategories'][i]
首先,匯入importFile函式,獲取儲存有效用例的字典,最終從其中獲取到需要的兩個變數群組名groupName和儲存位置Flag,測試程式即可使用這兩個變數。
效果評價
本文提出的用例的分離思想簡單易行,由於採用了XML編寫用例,通用性很強,這樣的一套用例不僅能夠跨平臺使用,也可以使用各種開發語言對其進行解析,適用於各種語言開發的終端軟體。
測試用例與測試程式的分離使得用例編寫和程式編寫可以獨立進行,程式設計人員可以把精力投入到測試程式的編寫中,測試用例由其他人員編寫和修改,既保證了用例的覆蓋率,又提升了測試程式的開發效率。
參考資料
《Dive in Python》