背景简介
在写一个自动化脚本时,要模拟发送网络请求,其中网络请求包含hid、md5、机器是64位还是32位等众多情况,而且这些因子还是不确定的,产品和开发可能会随时更改,这里我们就想通过自动化脚本根据这些因子全排列地自动去生成Case。
这里就怎么写个扩展性较好的生成全排列Case的代码,做下简单分享,具体前因后果请关注另外一篇文章(待发)。
问题分析
现在假设就下面这三个case
hid | md5 | 64位/32位 |
---|---|---|
123 | abc | 32 |
456 | cde | 64 |
现在又三个因子,每个因子2种情况,全排列就是8种,我们最容易想到的就是for循环,伪码如下:
for(hid)
for(md5)
for(64位/32位)
这样写起来简单,但是如果我们现在又加了一个因子,比如是否安装搜狗浏览器,这个带代码我们就需要去改了,得加一层循环。这样到最后代码不仅维护起来特别麻烦,而且不美观。
怎么办?
我想到的有两种解决办法:
递归解法
第一次在第一个数组去一个因子,递归调用去第二个数组取因子,直到取到最后一个数组,这时候就是一条完整的Case。然后每个数组遍历取元素,就可以得到所有路径了。
伪码如下(我们把所有因子以及对应的情况维护在一个文档,函数自己去文档按顺序读出所有因子,这部比较简单我就不多说了):
//dep表示当前是第几个因子,line代表一共有多少个因子void GetFullAz(int dep, int Line)
{
if(dep >= Line) //最后一个因子了
return;
for(int i = 1; i <= len(dep); i++) //遍历第dep个因子
GetFullAz(dep + 1,Line);
}
这里涉及一些路径记录的技巧,就不一一说说了,统一看附录代码
类似于状态压缩的解法
其实这里就是一个全状态为的枚举,我们用一位数记录一个因子的状态,最后将这些数合起来,从下到大枚举,得到的就是全状态。
示例:对于上面个例子,由于每个因子只有两种状态,我们就可以用三个二进制数来表示,那么合起来后就是一个三位的二进制数,最小值为0,最大值为7,我们从0枚举到7,就可以得到全状态。
伪码如下:
//将一个数字解码到各个位,以形成case,比如上面枚举0到7枚举到5时,先把5解码成101,让后去看101对应的情况,既:hid = 456 md5 = abc system = 64位void Decode(int state, int Line) //state当前状态位、line因子个数
{
printf("Case:%-4d ",CaseNum++);
for(int i = Line - 1; i >= 0; i--)
{
int Temp = state % FactorNum[i]; //FactorNum[i]第i个因子有多少种情况
state /= FactorNum[i];
cout<<CaseArr[i][0]<<" = "<<CaseArr[i][Temp+1]<<" ";
}
cout<<endl;
}
//枚举状态位for(int i = 0; i < State; i++)
{
Decode(i, Line);
}
总结
相信在做测试时我们遇到的有多因子的情况还是非常之多的,而且因子的改变也会经常发生,手工的话我们可以用一些工具生成正交试验或者就是全排列的用例,但是用自动化我们必须要去自己实现一遍对应的算法。这里给大家做下简单的分享,还望批评指正。
代码附录
/*
* main.cpp
*
* Created on: 2014-12-9
* Author: fangyu
*/#include <functional>#include <algorithm>#include <iostream>#include <sstream>#include <iomanip>#include <numeric>#include <cstring>#include <cassert>#include <cstdio>#include <string>#include <vector>#include <bitset>#include <queue>#include <stack>#include <cmath>#include <ctime>#include <list>#include <set>#include <map>using namespace std;
//#pragma comment(linker,"/STACK:102400000,102400000")string CaseArr[1000][100];
int FactorNum[1000], CaseNum;
//递归解法vector<int> CasePath;
void OutPut()
{
int Len = CasePath.size();
printf("Case:%-4d ",CaseNum++);
for(int i = 0; i < Len; i++)
{
cout<<CaseArr[i][0]<<" = "<<CaseArr[i][CasePath[i]]<<" ";
}
cout<<endl;
}
void GetFullAz(int dep, int Line)
{
if(dep >= Line)
{
OutPut();
return;
}
for(int i = 1; i <= FactorNum[dep]; i++)
{
//cout<<CaseArr[Line][0]<<" = "<<CaseArr[Line][i]<<" ";
//if(Line == 1) cout<<endl;
CasePath.push_back(i);
GetFullAz(dep + 1,Line);
CasePath.pop_back();
}
}
//状态压缩解法void Decode(int state, int Line)
{
printf("Case:%-4d ",CaseNum++);
//cout<<"Case:"<<CaseNum++<<" ";
for(int i = Line - 1; i >= 0; i--)
{
int Temp = state % FactorNum[i];
state /= FactorNum[i];
cout<<CaseArr[i][0]<<" = "<<CaseArr[i][Temp+1]<<" ";
}
cout<<endl;
}
int main()
{
freopen("testin.txt","r",stdin);
string FactorName;
int Line = 0;
int State = 1;
while(cin>>FactorName)
{
cin>>FactorNum[Line];
State *= FactorNum[Line];
CaseArr[Line][0] = FactorName;
for(int i = 1; i <= FactorNum[Line]; i++)
{
cin>>CaseArr[Line][i];
}
Line++;
//getchar();
}
//递归
CasePath.clear();
CaseNum = 1;
GetFullAz(0, Line);
//状态压缩// CaseNum = 1;// for(int i = 0; i < State; i++)// {// Decode(i, Line);// }
return 0;
}
/*testin.txt*/
Hid 3 11 22 33
Md5 3 qw as zx
SE 2 有 无
总结
以上是对工作过程中的一个小问题,做的一些总结,欢迎大家提出建议或疑问,另外,想要获取更多信息,请关注公众号"搜狗测试"