首页 > 代码库 > 自动化脚本中运到的一些简单算法

自动化脚本中运到的一些简单算法

背景简介

在写一个自动化脚本时,要模拟发送网络请求,其中网络请求包含hid、md5、机器是64位还是32位等众多情况,而且这些因子还是不确定的,产品和开发可能会随时更改,这里我们就想通过自动化脚本根据这些因子全排列地自动去生成Case。

这里就怎么写个扩展性较好的生成全排列Case的代码,做下简单分享,具体前因后果请关注另外一篇文章(待发)。

问题分析

现在假设就下面这三个case

hidmd564位/32位
123abc32
456cde64

现在又三个因子,每个因子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 有 无

总结

以上是对工作过程中的一个小问题,做的一些总结,欢迎大家提出建议或疑问,另外,想要获取更多信息,请关注公众号"搜狗测试"

自动化脚本中运到的一些简单算法