MBT框架(MTest)的實現(xiàn)用到的技術探討
MBT框架的實現(xiàn)需要用到2種技術:參數(shù)組合技術與代碼生成技術。
參數(shù)組合技術:抽象出測試場景的參數(shù),并對參數(shù)做等價類及邊界值分析后,利用迪卡爾乘積對多類參數(shù)進行組合,并過濾掉不需要組合,這里多半是用例建模時需要考慮。框架需要提供的是組合算法與過濾算法,用戶在使用這些算法的比較易懂、實用。
代碼生成技術:框架應能執(zhí)行模型代碼,執(zhí)行模型后能生成可執(zhí)行的測試代碼,這有點類似病毒,代碼執(zhí)行后,能產生出與自己等價的代碼。舉例如下:
原始模型代碼:
from MTest import TestCaseBase, Model, Scenario, Action, Assert, Logger @Action(DespFormat="Called with {0}, {1}") @Model() @Scenario(Param={ def TestJustReturnSelf(self): |
在執(zhí)行后,生成3個測試用例
@Model(TestModule="") @Scenario(Param={'p1': 1, 'p2': 'a'}) Logger.Step("Call JustReturnSelf and Validate") @Scenario(Param={'p1': 1, 'p2': 'b'}) Logger.Step("Call JustReturnSelf and Validate") @Scenario(Param={'p1': 2, 'p2': 'a'}) Logger.Step("Call JustReturnSelf and Validate") |
以SpecExplore為例:
<!--[if !supportLists]-->1. <!--[endif]-->開發(fā)出建模腳本,通過解析腳本結合接口定義生成出測試用例。但這樣的偽代碼的開發(fā)成本和使用難道都比較大,沒有語法檢查,幾乎靠經(jīng)驗摸索著使用。
<!--[if !supportLists]-->2. <!--[endif]-->利用對象的屬性值變化作為模型轉換的狀態(tài)。對于初學者,來定位一個模型邏輯問題,難度和要求都是很高的。
<!--[if !supportLists]-->3. <!--[endif]-->在執(zhí)行模型時,根據(jù)在腳本中對模型接口定義好的枚舉參數(shù)進行組合并且根據(jù)模型實現(xiàn)確定每一個參數(shù)。
在MTest中,建模與一般的寫測試用例的方式是一致,先進行參數(shù)組合,再執(zhí)行模型,模型通過一個全局屬性獲取參數(shù)或者直接傳給測試用例。為使能生成代碼,在執(zhí)行模型過程需要記住模型的執(zhí)行路徑,攔截住執(zhí)行每個接口函數(shù)調用的入?yún)⒑推诖妮敵觥F渲校诖妮敵鍪菑膶涌诘男r炛蝎@取。因此,攔截接口函數(shù)調用的入?yún)⑴c輸出是關鍵的技術。
從語言層面看,要攔截函數(shù)的入?yún)⒑洼敵觯?/p>
<!--[if !supportLists]-->1. <!--[endif]-->Java里有spring可以做些攔截,但創(chuàng)建對象的必須從spring的容器中獲取。即使通過這種攔截能達到上面的效果,將其引入測試,配置和使用會異常復雜。
<!--[if !supportLists]-->2. <!--[endif]-->C#跟Java類似,C++就更不可能了。
只能求助腳本語言了,Python語言的一個特性剛好可以做到這一點:獲取Python對象的屬性或函數(shù)都是通過__getattribute__來做到的,在定義類時覆蓋這個函數(shù),返回包裝好這個函數(shù)執(zhí)行的代理函數(shù),就可以攔截函數(shù)的入?yún)ⅰ?zhí)行和給出一個模擬的輸出。以一個例子說明如下:
class A: def __getattribute__(self, name): print("Here, can return a delegate for function: %s, not just itself" % name) return object.__getattribute__(self, name) def bFun(self): print('b Called') A().bFun() |
輸出:
Here, can return a delegate for function: bFun, not just itself
b Called
實際上,在mtest模式執(zhí)行模型時,MTest中對bFun的代理函數(shù)并不會真實的去執(zhí)行bFun,而是直接返會了一個動態(tài)結果DynamicResult,交給Assert.AreEqual去校驗,而Assert.AreEqual也不會被真正的執(zhí)行,而是僅僅是記住這個動態(tài)結果的期望值。這就知道了函數(shù)執(zhí)行時的入?yún)⒑洼敵觥R虼耍灰且玫絼討B(tài)結果的函數(shù)都應該是能被代理掉的。否則,這個函數(shù)得到將是一個未知的動態(tài)結果對象。從另外一個角度看,這實際上是對函數(shù)調用的一次Mock!
另注:MTest里標記為@Action的函數(shù)和所有以Logger和Assert開始的函數(shù)都是能被代理掉的;能生成Python的代碼,引入不同的代碼生成技術,同樣可以生成Java,C#,Ruby,JS、JMeter性能測試腳本的代碼