首页 > 编程语言 >Pairwise实现(Python篇)

Pairwise实现(Python篇)

时间:2024-05-23 16:21:24浏览次数:30  
标签:index Python 元素 实现 测试用例 Pairwise print line listb

开篇:

测试过程中,对于多参数参数多值的情况进行测试用例组织,之前一直使用【正交分析法】进行用例组织,说白了就是把每个参数的所有值分别和其他参数的值做一个全量组合,用Python脚本实现,就是itertools模块中product方法(又称笛卡尔积法)。

组合生成器,例:
    import itertools
    a = (1, 2, 3)
    b = ('A', 'B', 'C')
    c = itertools.product(a,b)
    for elem in c:
        print elem
    输出为:
    (1, 'A')
    (1, 'B')
    (1, 'C')
    (2, 'A')
    (2, 'B')
    (2, 'C')
    (3, 'A')
    (3, 'B')
    (3, 'C')

正交分析法的优点是测试用例覆盖率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函数为本人死磕出来的代码。

二、直接上代码

1 # -*- coding: utf-8 -*-
 2 from datetime import *
 3 import random,os,copy,time
 4 import logging
 5 import itertools
 6 '''
 7 #Author:Kuzaman
 8 #Time:2017-07-18
 9 '''
10 class utils2 :
11     #1、笛卡尔积 对参数分组全排列
12     def product(self,allparams):
13         newlist=[]
14         for x in eval('itertools.product'+str(tuple(allparams))):
15             newlist.append(x)
16         return newlist    
17     
18     #2、对笛卡尔积处理后的二维原始数据进行N配对处理,得到Pairwise计算之前的数据
19     def get_pairslist(self,productedlist,pairlen):
20         pwlist = []
21         for i in productedlist:
22             subtemplist = []
23             for sublista in itertools.combinations(i,pairlen):
24                 subtemplist.append(sublista)
25             pwlist.append(subtemplist)
26         return pwlist
27     
28     #3、进行Pirwise算法计算
29     def pairwise(self,allparams,pairlen):
30         productedlist=self.product(allparams)   #productedlist笛卡尔积全排列组合的测试用例
31         self.pprint(productedlist)  
32         print ('笛卡尔积全排列组合数量:',len(productedlist),'--'*11)        
33         listb = self.get_pairslist(productedlist,pairlen)   #listb:对测试用例结对拆分后的二维列表        
34         sublistlen = len(listb[1])  #sublistlen:每个测试用例拆分后一维列表长度
35         flag = [0]*sublistlen       #一条测试用例拆分后,每个结对在二维列表同位置上是否有相
36                                     #同值,其标识列表为flag,flag长度根据sublistlen改变        
37         templistb = copy.deepcopy(listb)#【有效组】的原始值与listb相同
38         delmenu = []    #无效测试用例编号列表
39         holdmenu=[]     #有效测试用例编号列表
40         # self.pprint (listb)
41         print ('--'*7,'有效测试用例计算结果','--'*7)
42         for cow in listb:           #一维遍历,等同于二维数组按照行遍历
43             for column in cow:      #二维遍历,等同二维数组中任意一行按照‘列’横向遍历
44                 for templistbcow in templistb:      #【有效组=templistb】中按照行,从上至下遍历
45                     Xa = cow.index(column)          #待校验元素的横坐标
46                     Ya = listb.index(cow)           #待校验元素的纵坐标
47                     #有效组中行不能是当前要对比元素所在的行,
48                     #且带对比元素与【有效组】的行templistbcow中的坐标Xa元素相同,
49                     #则认为对比成功,跳出第三层for循环。
50                     if templistbcow != cow and column == templistbcow[Xa]:
51                         # print (column,'===>' ,templistbcow[Xa],'相等了。。。')
52                         flag[Xa] = 1   #1表示对比成功
53                         break
54                     else: #对比不成功,需要继续第三层for循环对比
55                         # print (column,'===>' ,templistbcow[Xa],'不不不等了。。。')
56                         flag[Xa] = 0   #0表示对比不成功
57             # print ('下标%d,子元素 %s 双匹配对比结果flag:%s'%(listb.index(cow),cow,flag))
58             if 0 not in flag:    #如果对比列表中都是1,表明该行的所有结对都在同列的对应位置找到了
59                 num = listb.index(cow) 
60                 delmenu.append(num)     #记录该无用用例所在总列表listb中的位置
61                 templistb.remove(cow)   #有效组中删除该无用用例,保持有效性
62                 # print ('下标为%d行应删除,内容=%s,'%(num,cow))
63                 # print ('delmenu:',delmenu)
64             else:  #如果有0出现在对比列表flag中,则表示该行所有结对组并未全在同列对应位置找到,此用例为有效用例应保留
65                 num2 = listb.index(cow)  
66                 holdmenu.append(num2)     #记录有效用例在总列表listb中的坐标
67                 # print ('---------------下标为%d行应保留,内容=%s'%(num2,cow))
68                 # print('holdmenu=',holdmenu)
69             # print ('***'*20)
70         print ('保留元素列表:%s 匹配重复元素列表:%s'%(holdmenu,delmenu))
71         return self.pwresult(productedlist,holdmenu)
72 
73     def pwresult(self,slist,holdmenu):
74         holdparamslist = []
75         for  item in holdmenu:
76             holdparamslist.append(slist[item])
77         return holdparamslist
78 
79     def pprint(self,list):
80         for item in list:
81             print ('line %d:'%(list.index(item)+1),item)
82             # print (item) 
83 
84 if __name__ == '__main__':
85     u2 = utils2()
86     # allparams=[['M','O','P'],['W','L','I'],['C','E'
87     allparams=[['M','O','T'],['L','I','T'],['s','T','E','K'],[1,3],['Yes','No'],['666','']]
88     finallist = u2.pairwise(allparams,4)
89     print('最终保留测试用例个数:%d 个'%(len(finallist)))
90     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

见图:

 

完结篇

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

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

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

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

启蒙参考文章:感谢作者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

标签:index,Python,元素,实现,测试用例,Pairwise,print,line,listb
From: https://www.cnblogs.com/wi-Tim-n/p/18208757

相关文章

  • Pairwise实现(Java篇)
    importjava.util.HashMap;/***PairWise(成对)测试方法*author:likeqc*date:2021-4-411:06:59*/classPairWise{/***@paramstrString[][],二维数组,一维数组str[i]中存放第i个因素的因子*/privatestaticvoidsolution(String[][]s......
  • nodejs + express + mysql + redis 基础功能实现
    nodejs+express+mysql+redis基础功能实现yeyue  9人赞同了该文章本文大体介绍了nodejs项目的创建、express框架的使用、mysql数据库的连接、以及redis的数据交互等方法,并举例了些简单的例子进行说明,代码都是亲自重头跑了一遍的,拿来可用。 一、......
  • 如何批量在线实现pdf转epub?
    pdf怎么转成epub格式?相信很多小伙伴在处理PDF文件时会遇到各种各样的问题,比如pdf怎么转epub这个格式,这个时候我们该如何解决呢?我们也会在网上找到一些方法和教程,但往往下载一堆软件却并不能完全解决问题,下面教你一种能真正解决问题的批量在线pdf转epub方法,而且还免费哟。我们都知......
  • python多进程感悟
    对于大量的测试数据,使用多进程时(例如8个进程),最好使用queue来消费数据,不要将测试数据分为8个list,分别送入不同的进程中,因为这样可以避免极端情况出现。例如,每个测试数据处理起来耗时不一样,你刚好把耗时比较长的数据分了同一个list,就会导致其他的进程也会一直等待该进程的完成。......
  • uniapp实现左滑显示编辑删除按钮
     【使用时可删除不必要的内容,我就是记录一下】方法一:详细借鉴(app):http://www.aliyue.net/10130.html方法二:详细借鉴(微信小程序):https://blog.csdn.net/weixin_41579185/article/details/117747252?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-......
  • Python使用Argparse读取命令参数
    python编写的脚本需要通过命令参数来做一些参数配置。本文将介绍如何使用argparse来解析命令行参数。这种方法相对于sys.args的方式会简单很多。通过以下的脚本来构建一个简单的配置解析器,解析用户名、密码。importargparseimportsysdefmain():  args=sys.ar......
  • .NET快速实现网页数据抓取
    前言今天我们来讲讲如何使用.NET开源(MITLicense)的轻量、灵活、高性能、跨平台的分布式网络爬虫框架DotnetSpider来快速实现网页数据抓取功能。注意:为了自身安全请在国家法律允许范围内开发网页爬虫功能。网页数据抓取需求本文我们以抓取博客园10天推荐排行榜第一页的文章标......
  • BabyAGI 的原理和代码实现分析
    BabyAGI是一个人工智能驱动的任务管理系统,它使用OpenAI和PineconeAPI(向量数据库)来创建任务、确定优先级和执行任务。该系统使用OpenAI和矢量数据库(例如Chroma或Weaviate)来创建、确定优先级和执行任务。该系统背后的主要思想是,它根据先前任务的结果和预定义的目标创建......
  • SqlSugar : date绑定到XX失败,可以试着换一个类型,或者使用ORM自定义类型实现
    System.Exception:中文提示:date绑定到Machine失败,可以试着换一个类型,或者使用ORM自定义类型实现EnglishMessage:MachinedatebinderroratSqlSugarEntity(IDataRecord)atSqlSugar.IDataReaderEntityBuilder`1.Build(IDataRecorddataRecord)atSqlSugar.......
  • Linux下安装Python3
    前言Linux下大部分系统默认自带python2.x的版本,最常见的是python2.6或python2.7版本,默认的python被系统很多程序所依赖,比如centos下的yum就是python2写的,所以默认版本不要轻易删除,否则会有一些问题,如果需要使用最新的Python3那么我们可以编译安装源码包到独立目录,这和系统默认环......