下面小編就為大家帶來一篇高效測試案例組織演算法pairwise之Python實現方法。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
開篇:
測試過程中,對於多參數參數多值的情況進行測試案例組織,之前一直使用【正交分析法】進行用例組織,說白了就是把每個參數的所有值分別和其他參數的值做一個全量組合,用Python指令碼實現,就是itertools模組中product方法(又稱笛卡爾積法)。
正交分析法的優點是測試案例覆蓋率100%,缺點測試案例數量龐大,執行用例消耗的人工巨大。
Pairwise (結對)演算法源於對傳統的正交分析方法最佳化後得到的產物,它的理論來自於數學統計。毫不避諱的說,本人看不懂數學統計中的學術論文,只能從網上找一些通俗簡單的說法來理解其基本含義。
網上很多人都執行個體都是用 【作業系統,瀏覽器,語言環境】來舉例的,本人也做同樣樣本:
作業系統: W(Windows),L(Linux),Mac (Mac) ;瀏覽器:M(Firefox),O(Opera),IE;語言環境:C(中文),E(英文)
按照正交分析法:會產生3x3x2=18種組合方式 ,測試案例覆蓋率100%。
Pairwise結對測試案例組織法,可壓縮到9種組合方式。因此有點是 測試案例數量少,缺點是一定會有漏測。
引論:
Pairwise演算法的核心理念
1、一組測試案例(每個用例有3個參數的值組成,如[W,M,C])中每一個2個元素組合起來,兩兩組合,就有3種組合方式(有位置的[W,M][W,C][M,C]);
2、如果這第一組測試用兩兩組合出的3種組合方式,對比原則:[W,M]只會和其他組的第一個元素對比,[W,C]只會和其他組中第二個元素對比。。。。;
[W,M][W,C][M,C]這三個元素分別出現在其餘有效組位置相同的元素中,就可以認為這一組Case為多餘Case,並進行刪除。
名詞解釋:【有效組】表示未被刪除的組和未被對比過的組。舉例:第1,3組被刪除,則第4組要對比的有效組為第2,5,6,7...18組。有效組這裡踩過坑%>_<%
3、最終得到測試案例,就是結對演算法計算出來的最優測試案例集合。
牛逼閃閃的學術證明
Pairwise是L. L. Thurstone(29 May1887 – 30 September 1955)在1927年首先提出來的。他是美國的一位心理統計學家。Pairwise也正是基於數學統計和對傳統的正交分析法進行最佳化後得到的產物。
Pairwise基於如下2個假設:
(1)每一個維度都是正交的,即每一個維度互相都沒有交集。
(2)根據數學統計分析,73%的缺陷(單因子是35%,雙因子是38%)是由單因子或2個因子相互作用產生的。19%的缺陷是由3個因子相互作用產生的。
因此,pairwise基於覆蓋所有2因子的互動作用產生的用例集合性價比最高而產生的。
本文
一、思路
對一個測試情境如何從何從輸入被測條件,到產出Pairwise測試案例,使用Python編程思路如下:
1、將allparams=[['M','O','P'],['W','L','I'],['C','E']]進行笛卡爾積全組合處理,產生正則分析法產生的全量測試案例集合的一維數組(len=N);
2、將全量測試案例中的每個測試案例,都進行兩兩組合的分解處理,產生與全量測試案例集合 長度相同的二維數組(一維 len=N);
3、使用Python版Pairwise演算法剔除無效測試案例,最終得到有效結對測試案例集合;
代碼第1,2函數利用Python內建數學計算庫itertools編寫,代碼第3函數為本人死磕出來的代碼。
二、直接上代碼
# -*- coding: utf-8 -*-from datetime import *import random,os,copy,timeimport loggingimport itertools'''#Author:Kuzaman#Time:2017-07-18'''class utils2 : #1、笛卡爾積 對參數分組全排列 def product(self,tuple1): newlist=[] for x in eval('itertools.product'+str(tuple(tuple1))): newlist.append(x) return newlist #2、對笛卡爾積處理後的二維未經處理資料進行N配對處理,得到Pairwise計算之前的資料 def get_pairslist(self,lista): pwlist = [] for i in lista: subtemplist = [] for sublista in itertools.combinations(i, 2): subtemplist.append(sublista) pwlist.append(subtemplist) return pwlist #3、進行Pirwise演算法計算 def pairwise(self,listb): sublistlen = len(listb[1]) flag = [0]*sublistlen templistb = copy.deepcopy(listb) delmenu = [] holdmenu=[] self.pprint (listb) print ('--'*25) for lb in listb: for sublb in lb: for k in templistb: Xa = lb.index(sublb) Ya = listb.index(lb) if k != lb and sublb == k[Xa]: # print (sublb,'===>' ,k[Xa],'相等了。。。') flag[Xa] = 1 break else: # print (sublb,'===>' ,k[Xa],'不不不等了。。。') flag[Xa] = 0 # print ('下標%d,子項目 %s 雙匹配對比結果flag:%s'%(listb.index(lb),lb,flag)) if 0 not in flag: num = listb.index(lb) delmenu.append(num) templistb.remove(lb) # print ('下標為%d行應刪除,內容=%s,'%(num,lb)) # print ('delmenu:',delmenu) else: num2 = listb.index(lb) holdmenu.append(num2) # print ('下標為%d行應保留,內容=%s,'%(num2,lb)) # print('holdmenu=',holdmenu) # print ('***'*20) print ('保留元素列表:%s \n匹配重複元素列表:%s'%(holdmenu,delmenu)) return templistb def pwresult(self,slist,delmenu): for x in delmenu: slist.remove(slist[x]) return slist def pprint(self,list): for i in list: print ('line %d:'%(list.index(i)+1),i) if __name__ == '__main__': u2 = utils2() allparams=[['M','O','P'],['W','L','I'],['C','E']]#,'K'],[1,2,3],['Yes','No']] str = u2.product(allparams) strpc = u2.get_pairslist(str) finallist = u2.pairwise(strpc) print('最終保留測試案例個數:%d 個'%(len(finallist))) u2.pprint(finallist)
代碼解讀:
第三for迴圈代碼39~48行,主要是垂直判斷 待檢測元素 與 相同位置的元素是否有相同的
第二for迴圈代碼38~48行,把一組測試案例中的兩兩配對,從左至右分別和同位置的元素作對比
第一for迴圈代碼37~48行,遍曆每一組測試案例。
第50~58行代碼,判斷一組用例的兩兩配對在其他組同位置上從上到下都能找到相同元素,則將改無效Case從templistb中刪除,保持templistb的有效性。
執行結果:
line 1: [('M', 'W'), ('M', 'C'), ('W', 'C')] <---第二個函數get_pairslist(self,lista)處理後的兩兩配對組合line 2: [('M', 'W'), ('M', 'E'), ('W', 'E')] <---同第一行解釋line 3: [('M', 'L'), ('M', 'C'), ('L', 'C')]line 4: [('M', 'L'), ('M', 'E'), ('L', 'E')]line 5: [('M', 'I'), ('M', 'C'), ('I', 'C')]line 6: [('M', 'I'), ('M', 'E'), ('I', 'E')]line 7: [('O', 'W'), ('O', 'C'), ('W', 'C')]line 8: [('O', 'W'), ('O', 'E'), ('W', 'E')]line 9: [('O', 'L'), ('O', 'C'), ('L', 'C')]line 10: [('O', 'L'), ('O', 'E'), ('L', 'E')]line 11: [('O', 'I'), ('O', 'C'), ('I', 'C')]line 12: [('O', 'I'), ('O', 'E'), ('I', 'E')]line 13: [('P', 'W'), ('P', 'C'), ('W', 'C')]line 14: [('P', 'W'), ('P', 'E'), ('W', 'E')]line 15: [('P', 'L'), ('P', 'C'), ('L', 'C')]line 16: [('P', 'L'), ('P', 'E'), ('L', 'E')]line 17: [('P', 'I'), ('P', 'C'), ('I', 'C')]line 18: [('P', 'I'), ('P', 'E'), ('I', 'E')] <----同第一行解釋--------------------------------------------------保留元素列表:[1, 3, 4, 7, 9, 10, 12, 14, 17] <----有效用例在數組中下標匹配重複元素列表:[0, 2, 5, 6, 8, 11, 13, 15, 16] <----被剔除的無效測試案例在數組中下標最終保留測試案例個數:9 個line 1: [('M', 'W'), ('M', 'E'), ('W', 'E')]line 2: [('M', 'L'), ('M', 'E'), ('L', 'E')]line 3: [('M', 'I'), ('M', 'C'), ('I', 'C')]line 4: [('O', 'W'), ('O', 'E'), ('W', 'E')]line 5: [('O', 'L'), ('O', 'E'), ('L', 'E')]line 6: [('O', 'I'), ('O', 'C'), ('I', 'C')]line 7: [('P', 'W'), ('P', 'C'), ('W', 'C')]line 8: [('P', 'L'), ('P', 'C'), ('L', 'C')]line 9: [('P', 'I'), ('P', 'E'), ('I', 'E')][Finished in 0.2s]
三、代碼核心內容白話解釋
pairwise(self,listb)函數包含3層for迴圈,先畫一個二維數組:
i[0] i[1] i[2]listb.index(i)=0 : [('M', 'W'), ('M', 'C'), ('W', 'C')]listb.index(i)=1 : [('M', 'W'), ('M', 'E'), ('W', 'E')]listb.index(i) : [('M', 'L'), ('M', 'C'), ('L', 'C')]listb.index(i) : [('M', 'L'), ('M', 'E'), ('L', 'E')]listb.index(i) : [('M', 'I'), ('M', 'C'), ('I', 'C')]listb.index(i) : [('M', 'I'), ('M', 'E'), ('I', 'E')]listb.index(i) : [('O', 'W'), ('O', 'E'), ('W', 'E')]listb.index(i) : [('O', 'L'), ('O', 'C'), ('L', 'C')]listb.index(i) : [('O', 'L'), ('O', 'E'), ('L', 'E')]listb.index(i) : [('O', 'I'), ('O', 'C'), ('I', 'C')]listb.index(i)=n : [('O', 'I'), ('O', 'E'), ('I', 'E')]
二維列表 listb ,其中的行(發音:hang,二聲。橫著的那排)從上到下就是第一層for迴圈 ;每一行中的i[0],i[1],i[2]就是第二層for迴圈從左至右;第三次for迴圈元素i[x]從上之下與有效組 templistb通位置元素的對比。
1、第n行的i[0]要和有效templistb的其他行的i[0]元素對比(第三for),如果有相等的,記錄一個標識 如 flag1=True,如果沒有相等的記錄falg1=False;
2、直到第二for中的i[0],i[1],i[2]都進行對比後,會得到 [flag1,flag2,flag3 ],所有flag=True則該行為無效用例
3、第一for遍曆全部組合,最終得到保留下來的有效templistb
見圖:
完結篇
以上是自己編寫的pairwise的全部內容,此演算法共耗時3天:
第一天在確定這究竟是什麼演算法,看了很多學術文獻,看不懂;
第二天開始寫程式,for的嵌套迴圈設計耽誤很久;
第三天程式成型,有執行結果,發現與參考文章結論不同,隨後再仔細研讀參考文章,發現掉坑裡了。重新推翻代碼按照正確思路,用1個小時完成最終結果。
本人做測試的,還不是專業的測試開發,寫代碼比較費勁,真正應了設計佔70%,編碼佔30%的理。如果像基礎在差點,邏輯在亂點,就只能用時間堆了。