高效测试用例组织算法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,time
import logging
import itertools
'''
#Author:Kuzaman
#Time:2017-07-18
'''
class utils2 :
#1、笛卡尔积 对参数分组全排列
def product(self,allparams):
newlist=[]
for x in eval('itertools.product'+str(tuple(allparams))):
newlist.append(x)
return newlist #2、对笛卡尔积处理后的二维原始数据进行N配对处理,得到Pairwise计算之前的数据
def get_pairslist(self,productedlist,pairlen):
pwlist = []
for i in productedlist:
subtemplist = []
for sublista in itertools.combinations(i,pairlen):
subtemplist.append(sublista)
pwlist.append(subtemplist)
return pwlist #3、进行Pirwise算法计算
def pairwise(self,allparams,pairlen):
productedlist=self.product(allparams) #productedlist笛卡尔积全排列组合的测试用例
self.pprint(productedlist)
print ('笛卡尔积全排列组合数量:',len(productedlist),'--'*11)
listb = self.get_pairslist(productedlist,pairlen) #listb:对测试用例结对拆分后的二维列表
sublistlen = len(listb[1]) #sublistlen:每个测试用例拆分后一维列表长度
flag = [0]*sublistlen #一条测试用例拆分后,每个结对在二维列表同位置上是否有相
#同值,其标识列表为flag,flag长度根据sublistlen改变
templistb = copy.deepcopy(listb)#【有效组】的原始值与listb相同
delmenu = [] #无效测试用例编号列表
holdmenu=[] #有效测试用例编号列表
# self.pprint (listb)
print ('--'*7,'有效测试用例计算结果','--'*7)
for cow in listb: #一维遍历,等同于二维数组按照行遍历
for column in cow: #二维遍历,等同二维数组中任意一行按照‘列’横向遍历
for templistbcow in templistb: #【有效组=templistb】中按照行,从上至下遍历
Xa = cow.index(column) #待校验元素的横坐标
Ya = listb.index(cow) #待校验元素的纵坐标
#有效组中行不能是当前要对比元素所在的行,
#且带对比元素与【有效组】的行templistbcow中的坐标Xa元素相同,
#则认为对比成功,跳出第三层for循环。
if templistbcow != cow and column == templistbcow[Xa]:
# print (column,'===>' ,templistbcow[Xa],'相等了。。。')
flag[Xa] = 1 #1表示对比成功
break
else: #对比不成功,需要继续第三层for循环对比
# print (column,'===>' ,templistbcow[Xa],'不不不等了。。。')
flag[Xa] = 0 #0表示对比不成功
# print ('下标%d,子元素 %s 双匹配对比结果flag:%s'%(listb.index(cow),cow,flag))
if 0 not in flag: #如果对比列表中都是1,表明该行的所有结对都在同列的对应位置找到了
num = listb.index(cow)
delmenu.append(num) #记录该无用用例所在总列表listb中的位置
templistb.remove(cow) #有效组中删除该无用用例,保持有效性
# print ('下标为%d行应删除,内容=%s,'%(num,cow))
# print ('delmenu:',delmenu)
else: #如果有0出现在对比列表flag中,则表示该行所有结对组并未全在同列对应位置找到,此用例为有效用例应保留
num2 = listb.index(cow)
holdmenu.append(num2) #记录有效用例在总列表listb中的坐标
# print ('---------------下标为%d行应保留,内容=%s'%(num2,cow))
# print('holdmenu=',holdmenu)
# print ('***'*20)
print ('保留元素列表:%s \n匹配重复元素列表:%s'%(holdmenu,delmenu))
return self.pwresult(productedlist,holdmenu) def pwresult(self,slist,holdmenu):
holdparamslist = []
for item in holdmenu:
holdparamslist.append(slist[item])
return holdparamslist def pprint(self,list):
for item in list:
print ('line %d:'%(list.index(item)+1),item)
# print (item) if __name__ == '__main__':
u2 = utils2()
# allparams=[['M','O','P'],['W','L','I'],['C','E'
allparams=[['M','O','T'],['L','I','T'],['s','T','E','K'],[1,3],['Yes','No'],['','']]
finallist = u2.pairwise(allparams,4)
print('最终保留测试用例个数:%d 个'%(len(finallist)))
u2.pprint(finallist)
Pairwise Code
代码解读:
第三for循环代码39~48行,主要是垂直判断 待检测元素 与 相同位置的元素是否有相同的
第二for循环代码38~48行,把一组测试用例中的两两配对,从左至右分别和同位置的元素作对比
第一for循环代码37~48行,遍历每一组测试用例。
第50~58行代码,判断一组用例的两两配对在其他组同位置上从上到下都能找到相同元素,则将改无效Case从templistb中删除,保持templistb的有效性。
执行结果:
line 1: ('M', 'W', 'C')
line 2: ('M', 'W', 'E')
line 3: ('M', 'L', 'C')
line 4: ('M', 'L', 'E')
line 5: ('M', 'I', 'C')
line 6: ('M', 'I', 'E')
line 7: ('O', 'W', 'C')
line 8: ('O', 'W', 'E')
line 9: ('O', 'L', 'C')
line 10: ('O', 'L', 'E')
line 11: ('O', 'I', 'C')
line 12: ('O', 'I', 'E')
line 13: ('P', 'W', 'C')
line 14: ('P', 'W', 'E')
line 15: ('P', 'L', 'C')
line 16: ('P', 'L', 'E')
line 17: ('P', 'I', 'C')
line 18: ('P', 'I', 'E')
笛卡尔积全排列组合数量: 18 ----------------------
-------------- 有效测试用例计算结果 --------------
保留元素列表:[1, 3, 4, 7, 9, 10, 12, 14, 17]
匹配重复元素列表:[0, 2, 5, 6, 8, 11, 13, 15, 16]
最终保留测试用例个数:9 个
line 1: ('M', 'W', 'E')
line 2: ('M', 'L', 'E')
line 3: ('M', 'I', 'C')
line 4: ('O', 'W', 'E')
line 5: ('O', 'L', 'E')
line 6: ('O', 'I', 'C')
line 7: ('P', 'W', 'C')
line 8: ('P', 'L', 'C')
line 9: ('P', 'I', 'E')
[Finished in 0.6s]
Pairwise运行结果
如果我们要测试的参数组合是这样子的:
allparams=[['M','O','P'],['W','L','I'],['C','E','K'],[1,2,3],['Yes','No'],['666','']]
全排列组合会生成324种组合,按照 2元素结对的pairwise算法会缩减到41个有效组合;
按照 3元素结对的pairwise算法会缩减到88个有效测试用例;
按照 4元素结对的pairwise算法会缩减到114个有效测试用例。
↑这里整数可在代码91行进行调整
三、代码核心内容白话解释
pairwise(self,allparams,pairlen)函数包含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')]
二维列表,其中的行(发音: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的嵌套循环设计耽误很久;
第三天程序成型,有执行结果,发现与参考文章结论不同,随后再仔细研读参考文章,发现掉坑里了。重新推翻代码按照正确思路,用2个小时完成最终结果。
本人做测试的,还不是专业的测试开发,写代码比较费劲,真正应了设计占70%,编码占30%的理。
希望对需要组织测试用例,或者自动化测试中需要组织用例的同行们有所帮助。
启蒙参考文章:感谢作者aassddff261的文章 http://blog.csdn.net/aassddff261/article/details/42029325 http://blog.csdn.net/aassddff261/article/details/42776543
Python中list知识参考:http://www.runoob.com/python/python-lists.html
------------------------------------------本文原创,欢迎转载,请注明出处----------------------------------
高效测试用例组织算法pairwise之Python实现的更多相关文章
- FP-growth算法高效发现频繁项集(Python代码)
FP-growth算法高效发现频繁项集(Python代码) http://blog.csdn.net/leo_xu06/article/details/51332428
- DeepFM算法解析及Python实现
1. DeepFM算法的提出 由于DeepFM算法有效的结合了因子分解机与神经网络在特征学习中的优点:同时提取到低阶组合特征与高阶组合特征,所以越来越被广泛使用. 在DeepFM中,FM算法负责对一阶 ...
- 一个快速、高效的Levenshtein算法实现——代码实现
在网上看到一篇博客讲解Levenshtein的计算,大部分内容都挺好的,只是在一些细节上不够好,看了很长时间才明白.我对其中的算法描述做了一个简单的修改.原文的链接是:一个快速.高效的Levensht ...
- 光照问题之常见算法比较(附Python代码)
一.灰度世界算法 ① 算法原理 灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,R,G,B三个分量的平均值趋于同一灰度值Gray.从物理意义上讲,灰色世界法假设自然界景物 ...
- GBDT+LR算法解析及Python实现
1. GBDT + LR 是什么 本质上GBDT+LR是一种具有stacking思想的二分类器模型,所以可以用来解决二分类问题.这个方法出自于Facebook 2014年的论文 Practical L ...
- Robotium测试架构规划及测试用例组织
转自:http://blog.sina.com.cn/s/blog_68f262210102vrft.html 6.1 测试架构规划 由于测试用例执行的时候是在手机上执行的,所以类似于Web的把测试数 ...
- 策略设计测试用例实践(2)--Pairwise(转)
一.关于”好的“测试用例 在设计测试用例的时候有多种设计方法和策略可以使用,使得测试用例设计得更丰富,尽可能覆盖到更多的程序路径和功能场景.常见的测试用例设计方法被提到最多的就是等价类划分.边界值分析 ...
- 建模分析之机器学习算法(附python&R代码)
0序 随着移动互联和大数据的拓展越发觉得算法以及模型在设计和开发中的重要性.不管是现在接触比较多的安全产品还是大互联网公司经常提到的人工智能产品(甚至人类2045的的智能拐点时代).都基于算法及建模来 ...
- XMind2TestCase:一个高效测试用例设计的解决方案!
一.背景 软件测试过程中,最重要.最核心就是测试用例的设计,也是测试童鞋.测试团队日常投入最多时间的工作内容之一. 然而,传统的测试用例设计过程有很多痛点: 1.使用Excel表格进行测试用例设计,虽 ...
随机推荐
- matlab错误:Subscript indices must either be real positive integers or logicals.
matlab错误:Subscript indices must either be real positive integers or logicals. 中文解释:下标索引必须是正整数类型或者逻辑类 ...
- 深入理解CSS3 Flexbox
一.前言 Flexbox 是一个 CSS3 的盒子模型 ( box model ),顾名思义它就是一个灵活的盒子 ( Flexible Box ),为什麽最近这个属性才红起来呢?最主要也是因为 CSS ...
- Java 9 揭秘(1.Java入门介绍)
文 by / 林本托 在第一部分中,主要讲解如下内容: JDK 9 包含了哪些内容 运行代码的系统要求 如何安装 NetBeans 1 JDK 介绍 JDK 9是Java开发工具包的第九个主要版本,计 ...
- 让Chrome看不了WWDC直播的HLS技术详解
Requirements: Live streaming uses Apple's HTTP Live Streaming (HLS) technology. HLS requires an iPho ...
- 分清css的em和rem
在css中单位长度用的最多的是px.em.rem,这三个的区别是: px是固定的像素,一旦设置了就无法因为适应页面大小而改变. em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定 ...
- cpp(第七章)
1.c++提供了3种表示c—风格字符串方法:字符数组,字符串常量,字符串指针.其中字符数组并不一定是字符串,以空值字符'\0'来结束的字符数组时字符串. 2.函数参数为数组时,虽然减少了时间和内存的使 ...
- 如何让.Net线程支持超时后并自动销毁!
如何让.Net线程支持超时后并自动销毁! 1.使用CancellationTokenSource之基于Task实现方式 CancellationTokenSource source = new Can ...
- WPF中实现类智能感知
首先要做的事情就是定义一个popup来显示我们需要展示的东西 <Popup x:Name=" StaysOpen="False" Placement="B ...
- .net 4.0 中的特性总结(五):并行编程
1.任务并行库 从 .NET Framework 4 开始,TPL 是编写多线程代码和并行代码的首选方法. 但是,并不是所有代码都适合并行化:例如,如果某个循环在每次迭代时只执行少量工作,或它在很多次 ...
- Qlik报表开发见解
因为项目需要,最近去做了Qlik Sense报表开发,学习了Qlik报表的开发方法和一些基础的开发模式,以下是我对Qlik报表开发的一些见解,个人水平有限,欢迎大神指导. 1.Qlik Sense的函 ...