白盒测试之基本路径测试法

有更多的实现方法,这里只是分享思路,拒绝直接使用源码从事一切学习作业相关的提交!!!

白盒测试的一种常用方法是基本路径法,根据源代码构造程序流程图,转换为控制流程图,得到基本路径,进而为每条基本路径设计测试用例。基本路径法的一个关键步骤是识别出所有的基本路径。

下面是测试用例:

下面的代码已经不是最新的,每次完善(修复BUG,增加功能)后的代码均已托管:whiteBoxTestExtendArc.cpp!!!

左侧给出的是控制流图,相应的输入数据如右侧所示。

(支持大于2位的结点信息,测试样例请参考:https://github.com/luofei2011/White-box-testing --->test.txt)

输出格式如下:

其中CC为圈的复杂度,而且每条路径按照长度大小的原则排序,长度相同的比较各结点进行排序。



*2012-11-10更新:对任何一个或者多个判定结点可以附加OR or AND,以此来生成若干新行。

*2012-11-12更新:优化完善遍历算法,缩短遍历时间。优化改善排序算法,修复已知BUG。

输入数据中除了边信息之外,后续增加若干新行(与原有各行之间通过一行“EXT”分隔),每一行表示控制流图中的判断节点信息,例如:

1, AND
3, OR

分别表示节点1是 if (A && B) 的形式、节点3是if (A || B)的形式。

只考虑and/or两种逻辑运算符,且只考虑包含两个单一条件表达式(A, B)的复合的情况。

为应对上述情况,你的程序应对原有控制流图进行修改,使之变为标准的控制流图的形式,再生成圈复杂度和基本路径作为输出。修改控制流图后若需要引入新的节点,其编号可采用11、12、31、32(为消除BUG,只支持分离后的结点不会与原始结点重名:比如不会出现原来有一个叫42的结点,现在分离出来一个名为42的结点)来表示。

以下给出了一个例子(AND),前一个是输入,后一个为输出。


再给出一个OR的例子:


实现方法:

1.数据结构采用有向图的十字链表存储。

十字链表(Orthogonal List)是有向图的另一种链式存储结构,可以看成是将有向图的邻接表和逆邻接表结合起来得到的一种链表。------>摘自《数据结构(C语言版)--清华大学出版》

我们可以理解为将结点和弧连接起来的“网”,并且其中的每个结点都是“非零”的元素。


可以这样想:

用链表模拟矩阵的行(或者列,这可以根据个人喜好来定),然后,再构造代表列的链表,将每一行中的元素节点插入到对应的列中去。十字链表的逻辑结构就像是一个围棋盘(没见过,你就想一下苍蝇拍,这个总见过吧),而非零元就好像是在棋盘上放的棋子,总共占的空间就是,确定那些线的表头节点和那些棋子代表的非零元节点。最后,我们用一个指针指向这个棋盘,这个指针就代表了这个稀疏矩阵。


在十字链表中,对应于有向图中每一条弧有一个结点,对应于每个顶点也有一个结点,这些结构如下:


弧结点中:

尾域(tailvex):弧尾所在位置;

头域(headvex):弧头所在位置;

hlink,tlink:分别指向弧头/尾相同的下一条弧(在本次遍历过程中很有用);

info:该弧信息(本次项目中用来存储T/F/N).

头结点:

data:顶点相关的信息;

firstin,firstout:一该结点为弧头/尾的“第一个”结点。

以下是一个例子:


2.寻找基本路径采用非递归的深度优先搜索实现(DFSTraverse)。

基本思路是:

从头结点开始(需要找到头结点),采用深度优先搜索策略,若遇到判定结点,需“先F,后T”;若“N”则直接正常处理,这里的“先F,后T”就需要把T弧“压栈”(我只用数组实现),当循环到没有以当前结点为弧尾时则停止深度搜索->弹栈。或者当遇到“圈”时,代表路径重复,需要停止深度搜索--->弹栈。如此便能遍历该有向图。(这是最终版本,基本发现的BUG,错误均已修复!

#include<iostream>
#include<stdlib.h>
#include<malloc.h>
#include<string>
#include<cstring>
#define MAX 512 //允许输入的最大结点数
using namespace std;

//char arcArr[MAX][MAX]={'\0'};
int arcTail[MAX]={0};
int arcHead[MAX]={0};
char Judge[MAX]={'\0'};
int vexArr[MAX]={0};
int basic_path[MAX];//存储基本路径,并实时更新 
int CC = 0; //圈复杂度:(1)判定结点数+1;(2)e(边)-n(结点)+2 
char is_EXT = 'N';
string order_out = "";
//string ordered = "";

typedef struct  arcNode{
        int tail,head;  //弧的尾结点和头结点的位置
        struct arcNode *hlink, *tlink;      //弧头或弧尾相同的弧链表
        char judge;   //T/F/N    
}arcNode;

typedef struct vexNode{
        int data;
        bool visited;   
        arcNode *fin, *fout; //分别指向该顶点的第一条入弧和出弧        
}vexNode;

typedef struct{
        vexNode list[MAX]; //表头向量顶点列表
        int vnum, anum; //有向图当前的顶点和弧数        
}Graph;

bool is_end(string str){
    // transform(str.begin(),str.end(), str.begin(), ::toupper);
     if(str == "END" || str == "end" || str == "EXT" || str == "ext")
            return true;
     return false;
}

int length(int num[]){
    int sum=0;
    for(int i=0; i<MAX; i++){
          if(num[i] != 0)
                sum++; 
          else
              break;
    }
    return sum;   
}

bool is_inArr(int ch[],int in){
     for(int i=0; i<length(ch); i++)
             if(in == ch[i])
                   return true;
     return false;
}

void insert(string str){
     int pos = length(vexArr);
     int i = length(arcTail);
     string _tail = str.substr(0,str.find('-'));
     string _head = str.substr(str.find('>')+1,str.find(',')-str.find('>')-1);
     char _judge = str[str.size()-1];
     if(!is_inArr(vexArr, atoi(_tail.c_str())))
          vexArr[pos++] = atoi(_tail.c_str());
     if(!is_inArr(vexArr, atoi(_head.c_str())))
          vexArr[pos++] = atoi(_head.c_str());
     arcTail[i] = atoi(_tail.c_str());
     arcHead[i] = atoi(_head.c_str());  
     Judge[i] = _judge;         
}

int LocateVex(Graph *G, int vertex){
    int j=0,k;
    for(k=0; k<length(vexArr); k++)
             if(G->list[k].data == vertex){
                   j = k;
                   break;                   
             }    
    return j;
}

void CreateGraph(Graph *G){
     //初始化顶点列表 
     int _tail, _head;
     arcNode *arcTemp;
     G->vnum = G->anum =0;
     for(int i=0; i<length(vexArr); i++){
             (*G).list[i].data = vexArr[i];
             G->list[i].fin = NULL;
             G->list[i].fout = NULL;  
             G->vnum++;  
             G->list[i].visited = false;
     }     
     //初始化弧并构建十字链表
     for(int i=0; i<length(arcTail); i++){
             if(Judge[i] == 'T')
                     CC ++;
             _tail = LocateVex(G,arcTail[i]);
             _head = LocateVex(G,arcHead[i]);
             arcTemp = (arcNode*)malloc(sizeof(arcNode));
             arcTemp->tail = _tail;
             arcTemp->head = _head;
             arcTemp->tlink = (*G).list[_tail].fout;
             (*G).list[_tail].fout = arcTemp;
             arcTemp->hlink = (*G).list[_head].fin;
             (*G).list[_head].fin = arcTemp;
             arcTemp->judge = Judge[i]; 
             G->anum++;                       
     } 
}


void display(Graph *G,int arr[]){
     char ch[10];
     int temp =0;
     char is_no = 'N';
     for(int i=0; i<length(arr)-1; i++){
             string Arc = "";
             temp = arr[i];
             snprintf(ch,sizeof(ch),"%d",temp);
             Arc += ch;
             Arc += ",";
             temp = arr[i+1];
             snprintf(ch,sizeof(ch),"%d",temp);
             Arc += ch;
             if(order_out.find(Arc) != order_out.npos) 
                      continue;
             else{
                 is_no = 'Y';
                 break;
             } 
             i += 1;     
     }
     if(is_no == 'Y'){
              memset(ch,0,10);
     for(int i=0; i<length(arr)-1; i++){
             temp = arr[i];
             snprintf(ch,sizeof(ch),"%d",temp);
             order_out += ch;
             order_out += ",";
     }
     memset(ch,0,10);
     snprintf(ch,sizeof(ch),"%d",arr[length(arr)-1]);
     order_out += ch;
     order_out += "|"; 
     }
}

int my_memset(int arr[],int _data){
     int pos = 0;
     int _length = length(arr);
     for(int i=0; i<_length; i++)
           if(_data == arr[i]){
                     pos = i;
                     break;
           }
     //不能使用i<length(arr)清空arr的时候length(arr)就会改变 
     for(int i=pos+1; i<_length; i++)
             arr[i] = 0;  
     //display(arr); 
     return pos;  
}

void changeVisited(Graph *G,int arr[], int num){
     char is_find_ = 'N';
     int pos =0;
     for(int i=0; i<length(arr); i++){
             if(arr[i] == num){
                       is_find_ = 'Y';
                       i++;          
             }    
             if(arr[i] != 0)
                       if(is_find_ == 'Y'){    
                                pos = LocateVex(G,arr[i]);
                               // cout << "pos:" << pos << endl;
                                G->list[pos].visited = false;
                               // cout << "data:" << G->list[pos].data << endl;
                       }
     }     
}

//有向图十字链表结构的深度优先非递归遍历 
void DFSTraverse(Graph G, int pos){
     arcNode *p;
    // int _pos = 0; //记录不同路径的分离点 
     arcNode *Queue[MAX*MAX];
     int Vex[MAX]={0};
     int _len_=0;
     int queue = -1;
     int pointer = -1;
     p = G.list[pos].fout;
     basic_path[++pointer] = G.list[pos].data;
     if(!p){
           display(&G,basic_path);
           return;
     }
     while(p){ 
           if(!is_inArr(basic_path,G.list[p->tail].data))
                  basic_path[++pointer] = G.list[p->tail].data;
           if(p->judge != 'N'){ 
                       //若遇到先前遍历过的结点则直接走F就行,T不予考虑 
                  if(is_inArr(Vex,G.list[p->tail].data) && (!G.list[p->tail].visited)){
                            if(p->judge == 'T')
                                        p = p->tlink;
                  }
                  else{
                       if((p->judge == 'T') && (!G.list[p->tail].visited)){
                       // if(p->judge == 'T'){
                             Queue[++queue] = p;
                             p = p->tlink;
                       }
                       else if(p->judge == 'F')
                            Queue[++queue] = p->tlink; 
                       G.list[p->tail].visited = true;
                       if(!is_inArr(Vex,G.list[p->tail].data))
                            Vex[_len_++] = G.list[p->tail].data; 
                  }
           }
           if(is_inArr(basic_path,G.list[p->head].data)){
                  basic_path[++pointer] = G.list[p->head].data;  
                  if(queue >= 0){ 
                                display(&G,basic_path);         
                                p = Queue[queue];
                                queue --; 
                                pointer = my_memset(basic_path,G.list[p->tail].data);     
                                changeVisited(&G,Vex,G.list[p->tail].data);
                  }
                  //不加else会导致死循环,因为到最后一层的时候数组为空。直接把头结点加入到循环队列中 
                  else{  
                         display(&G,basic_path); 
                         break;
                  } 
                  continue;                                            
           }
           basic_path[++pointer] = G.list[p->head].data;
           pos = LocateVex(&G,G.list[p->head].data);
           p = G.list[pos].fout;
           if(!p){
                if(queue >= 0){     
                      display(&G,basic_path); 
                      p = Queue[queue];
                      queue --;  
                      pointer = my_memset(basic_path,G.list[p->tail].data);
                      changeVisited(&G,Vex,G.list[p->tail].data);//每次出栈需要改变后续结点的访问visited值
                }
                else{
                     display(&G,basic_path);
                     break;     
                }
           }
           
     }/*
     for(int i=0; i<length(Vex);i++)
             cout << Vex[i];
    cout << endl;*/
}

int returnNum(string str,char ch){
    int sum =0;
    while(str.size()){
          int pos = str.find(ch);
          if(pos != str.npos){
               str = str.substr(pos+1);
               sum++; 
          }
          else 
               break;          
    }
    return sum+1;
        
}

void remove_(string str){
     int pos = order_out.find(str);
     order_out.replace(pos,str.size()+1,"");     
}
//基本路径结点大小排序(路径长度相同的情况下)
bool my_compare(string str1,string str2){
     //cout << str1 << endl;
     //cout << str2 << endl;
     str1 += ",";
     str2 += ",";
     string temp1 = "";
     string temp2 = "";
     int pos1 = str1.find(',');
     int pos2 = str2.find(',');
     while(str1.size()){
              temp1 = str1.substr(0,pos1);
              temp2 = str2.substr(0,pos2);
              if(atoi(temp1.c_str()) > atoi(temp2.c_str()))
                      return true;  
              else if(atoi(temp1.c_str()) < atoi(temp2.c_str()))
                  return false;
              str1 = str1.substr(pos1+1);
              pos1 = str1.find(',');
              str2 = str2.substr(pos2+1);  
              pos2 = str2.find(',');                
     }     
}

void orderDisplay(string str){
     //cout << "CC=" << returnNum(str,'|')-1 << endl;
     string ordered = "";
     string _str = str;
     string small = str;
     int small_num = 100;
     string temp = "";
     char is_end = 'N';
     int pos = str.find('|');
     while(str.size()){
     for(int i=0; i<_str.size(); i++){
           temp = _str.substr(0,pos);
           if(returnNum(temp,',') < small_num){
                        small = temp;
                        small_num = returnNum(temp,',');
           }
           else if(returnNum(temp,',') == small_num)
                 if(my_compare(small,temp)){
                              small = temp; 
                              small_num = returnNum(temp,',');
                 }
           if(is_end == 'N'){
                _str = _str.substr(pos+1);  
                pos = _str.find('|');
                if(pos != _str.npos)
                     continue;
                else{
                     pos = _str.size();
                     is_end = 'Y';     
                } 
           } 
           else
               break;   
     }
     //cout << small << endl;
     ordered += small;
     ordered += "|";
     int _pos = str.find(small);
     str.replace(_pos,small.size()+1,"");
     _str = small = str;
     small_num =100;
     pos = str.find('|');
     is_end = 'N';
     }     
     order_out = ordered;  
}

void coutResult(string str){
     int pos = str.find('|');
     string temp;
     while(str.size()){
              temp = str.substr(0,pos);
              cout << temp << endl;
              str = str.substr(pos+1);
              pos = str.find('|');                  
     }
}

void changeVexArr(int num){
     for(int i=0; i<length(vexArr); i++)
             if(vexArr[i] == num){
                   vexArr[i] = num*10 + 1;
                   vexArr[length(vexArr)] = num*10 + 2;
                   break;             
             }             
}

void CreatePath(string str){	//当输入数据中含有AND,OR时需在原有弧的基础上增加
     string _vertex = str.substr(0,str.find(','));
     string _condition = str.substr(str.find(',')+1);
     int _num = atoi(_vertex.c_str());
     int _T = 0,_F = 0,_in[MAX]={0};
     int l = length(arcTail);
     int l_l =0;
     changeVexArr(_num);  
     
     for(int i=0; i<l; i++)
                   if(arcHead[i] == _num)
                          _in[l_l++] = i;                    
     for(int j=0; j<l; j++){
                   if((Judge[j] == 'F') && (arcTail[j] == _num))
                        _F = j;
                   else if((Judge[j] == 'T') && (arcTail[j] == _num)) 
                        _T = j;                            
     }
     for(int i=0; i<l_l; i++)
                   arcHead[_in[i]] = _num*10+1;
     if(_condition == "AND"){   
           int _into = length(arcTail);
           arcTail[_F] = _num*10+1;   
           arcTail[_into] = _num*10+1;   
           arcHead[_into] = _num*10+2;
           Judge[_into] = 'T';
           _into ++;
           arcTail[_T] = _num*10+2;
           arcTail[_into] = _num*10+2;
           arcHead[_into] = arcHead[_F];
           Judge[_into] = 'F';
     }
     else if(_condition == "OR"){
           int _into = length(arcTail);
           arcTail[_T] = _num*10+1;
           arcTail[_into] = _num*10+1;
           arcHead[_into] = _num*10+2;
           Judge[_into] = 'F';
           _into++;
           arcTail[_F] = _num*10+2;
           arcTail[_into] = _num*10+2;
           arcHead[_into] = arcHead[_T];
           Judge[_into] = 'T';
     }
}

void xianshi(){
    for(int i=0; i<length(vexArr); i++)
            cout << vexArr[i] << endl;
    for(int i=0; i<length(arcTail); i++)
            cout << arcTail[i] << "->" << arcHead[i] << "," << Judge[i] << endl;     
}

int main(){
    Graph G;
    int i=0;
    string temp ="";
    int _header = 0;
    getline(cin,temp);
    if(temp == "END")
            return 0;
    vexArr[i++] = atoi(temp.c_str());
    while(1){
             getline(cin,temp);
             if(temp == "EXT" || temp == "ext")
                   is_EXT = 'Y';
             if(is_end(temp)) 
                   break;
             insert(temp);        
    }
    if(is_EXT == 'Y')
             while(1){
                      getline(cin,temp);
                      if(is_end(temp))
                            break;
                      CreatePath(temp); 
                     // xianshi();        
             }
    //xianshi();
    CreateGraph(&G);
    DFSTraverse(G,LocateVex(&G,vexArr[0]));
    cout << "CC=" << returnNum(order_out,'|')-1 << endl;
    for(int i=0;i<10;i++)	//很奇葩的地方,需要进行多次重复排序
            orderDisplay(order_out);
    coutResult(order_out);
    //orderDisplay(ordered);
    //system("pause");
    return 0;   
}

最新代码: https://github.com/luofei2011/White-box-testing

About Me:luofeihit2010@gmail.com


  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值