您的位置:首页 > 其它

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

2012-11-08 21:00 288 查看
有更多的实现方法,这里只是分享思路,拒绝直接使用源码从事一切学习作业相关的提交!!!

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

下面是测试用例:

下面的代码已经不是最新的,每次完善(修复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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: