MBT框架(MTest)的實現用到的技術探討
MBT框架的實現需要用到2種技術:參數組合技術與代碼生成技術。
參數組合技術:抽象出測試場景的參數,并對參數做等價類及邊界值分析后,利用迪卡爾乘積對多類參數進行組合,并過濾掉不需要組合,這里多半是用例建模時需要考慮。框架需要提供的是組合算法與過濾算法,用戶在使用這些算法的比較易懂、實用。
代碼生成技術:框架應能執行模型代碼,執行模型后能生成可執行的測試代碼,這有點類似病毒,代碼執行后,能產生出與自己等價的代碼。舉例如下:
原始模型代碼:
from MTest import TestCaseBase, Model, Scenario, Action, Assert, Logger @Action(DespFormat="Called with {0}, {1}") @Model() @Scenario(Param={ def TestJustReturnSelf(self): |
在執行后,生成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]-->開發出建模腳本,通過解析腳本結合接口定義生成出測試用例。但這樣的偽代碼的開發成本和使用難道都比較大,沒有語法檢查,幾乎靠經驗摸索著使用。
<!--[if !supportLists]-->2. <!--[endif]-->利用對象的屬性值變化作為模型轉換的狀態。對于初學者,來定位一個模型邏輯問題,難度和要求都是很高的。
<!--[if !supportLists]-->3. <!--[endif]-->在執行模型時,根據在腳本中對模型接口定義好的枚舉參數進行組合并且根據模型實現確定每一個參數。
在MTest中,建模與一般的寫測試用例的方式是一致,先進行參數組合,再執行模型,模型通過一個全局屬性獲取參數或者直接傳給測試用例。為使能生成代碼,在執行模型過程需要記住模型的執行路徑,攔截住執行每個接口函數調用的入參和期待的輸出。其中,期待的輸出是從對接口的校驗中獲取。因此,攔截接口函數調用的入參與輸出是關鍵的技術。
從語言層面看,要攔截函數的入參和輸出:
<!--[if !supportLists]-->1. <!--[endif]-->Java里有spring可以做些攔截,但創建對象的必須從spring的容器中獲取。即使通過這種攔截能達到上面的效果,將其引入測試,配置和使用會異常復雜。
<!--[if !supportLists]-->2. <!--[endif]-->C#跟Java類似,C++就更不可能了。
只能求助腳本語言了,Python語言的一個特性剛好可以做到這一點:獲取Python對象的屬性或函數都是通過__getattribute__來做到的,在定義類時覆蓋這個函數,返回包裝好這個函數執行的代理函數,就可以攔截函數的入參、執行和給出一個模擬的輸出。以一個例子說明如下:
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模式執行模型時,MTest中對bFun的代理函數并不會真實的去執行bFun,而是直接返會了一個動態結果DynamicResult,交給Assert.AreEqual去校驗,而Assert.AreEqual也不會被真正的執行,而是僅僅是記住這個動態結果的期望值。這就知道了函數執行時的入參和輸出。因此,只要是引用到動態結果的函數都應該是能被代理掉的。否則,這個函數得到將是一個未知的動態結果對象。從另外一個角度看,這實際上是對函數調用的一次Mock!
另注:MTest里標記為@Action的函數和所有以Logger和Assert開始的函數都是能被代理掉的;能生成Python的代碼,引入不同的代碼生成技術,同樣可以生成Java,C#,Ruby,JS、JMeter性能測試腳本的代碼