高效测试用例组织算法pairwise之Python实现方法


Posted in Python onJuly 19, 2017

开篇:

测试过程中,对于多参数参数多值的情况进行测试用例组织,之前一直使用【正交分析法】进行用例组织,说白了就是把每个参数的所有值分别和其他参数的值做一个全量组合,用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,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之Python实现方法

完结篇

以上是自己编写的pairwise的全部内容,此算法共耗时3天:

第一天在确定这究竟是什么算法,看了很多学术文献,看不懂;

第二天开始写程序,for的嵌套循环设计耽误很久;

第三天程序成型,有执行结果,发现与参考文章结论不同,随后再仔细研读参考文章,发现掉坑里了。重新推翻代码按照正确思路,用1个小时完成最终结果。

本人做测试的,还不是专业的测试开发,写代码比较费劲,真正应了设计占70%,编码占30%的理。如果像基础在差点,逻辑在乱点,就只能用时间堆了。

希望对需要组织测试用例,或者自动化测试中需要组织用例的同行们有所帮助。

这篇高效测试用例组织算法pairwise之Python实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python数据库操作常用功能使用详解(创建表/插入数据/获取数据)
Dec 06 Python
python的即时标记项目练习笔记
Sep 18 Python
python有证书的加密解密实现方法
Nov 19 Python
九步学会Python装饰器
May 09 Python
python实现百度语音识别api
Apr 10 Python
pytorch cnn 识别手写的字实现自建图片数据
May 20 Python
使用Python自动化破解自定义字体混淆信息的方法实例
Feb 13 Python
django删除表重建的实现方法
Aug 28 Python
python解析命令行参数的三种方法详解
Nov 29 Python
pytorch 利用lstm做mnist手写数字识别分类的实例
Jan 10 Python
浅谈keras使用中val_acc和acc值不同步的思考
Jun 18 Python
Opencv 图片的OCR识别的实战示例
Mar 02 Python
Python实现将文本生成二维码的方法示例
Jul 18 #Python
Python实现动态加载模块、类、函数的方法分析
Jul 18 #Python
Python使用plotly绘制数据图表的方法
Jul 18 #Python
python中日志logging模块的性能及多进程详解
Jul 18 #Python
浅谈python中的__init__、__new__和__call__方法
Jul 18 #Python
Pycharm编辑器技巧之自动导入模块详解
Jul 18 #Python
python对DICOM图像的读取方法详解
Jul 17 #Python
You might like
php中判断数组相等的方法以及数组运算符介绍
2015/03/30 PHP
php设计模式之模板模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
javascript prototype,executing,context,closure
2008/12/24 Javascript
Jquery中Ajax 缓存带来的影响的解决方法
2011/05/19 Javascript
JavaScript实现存储HTML字符串示例
2014/04/21 Javascript
javascript元素动态创建实现方法
2015/05/13 Javascript
基于jQuery实现的旋转彩圈实例
2015/06/26 Javascript
利用HTML5的画布Canvas实现刮刮卡效果
2015/09/06 Javascript
Javascript在IE和Firefox浏览器常见兼容性问题总结
2016/08/03 Javascript
JS基于HTML5的canvas标签实现炫目的色相球动画效果实例
2016/08/24 Javascript
基于bootstrap实现多个下拉框同时搜索功能
2017/07/19 Javascript
Vue 自定义动态组件实例详解
2018/03/28 Javascript
为jquery的ajax请求添加超时timeout时间的操作方法
2018/09/04 jQuery
Js中使用正则表达式验证输入是否有特殊字符
2018/09/07 Javascript
AngularJS上传文件的示例代码
2018/11/10 Javascript
jQuery实现的点击显示隐藏下拉菜单功能完整示例
2019/05/17 jQuery
vue项目配置使用flow类型检查的步骤
2020/03/18 Javascript
vue接口请求加密实例
2020/08/11 Javascript
[02:30]联想杯DOTA2完美世界全国高校联赛—北京站现场
2015/11/16 DOTA
[44:43]完美世界DOTA2联赛决赛日 FTD vs GXR 第一场 11.08
2020/11/11 DOTA
[01:00:14]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant BO3 第二场 2月28日
2021/03/11 DOTA
使用Python判断IP地址合法性的方法实例
2014/03/13 Python
python中字符串比较使用is、==和cmp()总结
2018/03/18 Python
spark: RDD与DataFrame之间的相互转换方法
2018/06/07 Python
python无限生成不重复(字母,数字,字符)组合的方法
2018/12/04 Python
12个步骤教你理解Python装饰器
2019/07/01 Python
Spring实战之使用util:命名空间简化配置操作示例
2019/12/09 Python
python脚本后台执行方式
2019/12/21 Python
如何向scrapy中的spider传递参数的几种方法
2020/11/18 Python
对于没有初始化的变量的初始值可以作怎样的假定
2014/10/12 面试题
函授毕业生自我鉴定
2013/11/06 职场文书
《四季》教学反思
2014/04/08 职场文书
药剂专业自荐信范文
2014/04/16 职场文书
电教室标语
2014/06/20 职场文书
国家税务局领导班子对照检查材料思想汇报
2014/10/04 职场文书
幼儿园大班教师个人工作总结
2015/02/05 职场文书