自動化測試用例排序(三個算法隨機、貪心、額外貪心)


接着前面自動化測試的測試用例生成和收集,下面我們就需要做的是對測試用例進行排序,簡單來說就是達到語句的全部覆蓋。說到排序就涉及到三個算法,下面就是我對三個算法的闡述及代碼實現。咱們由易入難。

 

1’自動用例生成(使用Randoop)>

2‘評價(對用例篩選冗余)>功能覆蓋、語句覆蓋(一般用后者)

           >插樁  (插入語句)

              用Javassist實現自動插入語句

3’測試用例排序排序>三種算法實現測試用例排序

    1‘  隨機算法:測試用例會排序就是生成一個用例序列,隨機算法就是隨機生成一個測試用例序列

      下面是對序列進行打亂隨機排序的兩種方法:

//(1)利用math的random方法
List l=new ArrayList( input); //將input數組放入arraylist,input為集合 List res=new ArrayList(); //用來存放隨機產生元素的結果 Random r=new Random();//隨機數 int size=l.size(); for(int i=0;i<size;i++){ res.add(l.remove( r.nextInt(l.size()))); //為了保證不重復,每次隨機產生后都刪除該元素。 } //此時res中存放的就是隨機排序的結果。
//(2)利用collections的buffle方法
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
 public class Test {
List list = new LinkedList(); public static void main(String[] args) { List list = new LinkedList(); for ( int i = 0 ; i < 9 ; i ++ ) { list.add( " a " + i); } Collections.sort(list); // 順序排列 System.out.println(list); Collections.shuffle(list); //隨機打亂一個序列 System.out.println(list); Collections.reverse(list); // 倒序排列 System.out.println(list); System.out.println(Collections.binarySearch(list, " a5 " )); // 折半查找 }

     對此我簡單的用list輸入一個測試用例序列並進行隨機排序,輸出結果:   

package testpaixu;

import java.util.*;

public class randomA {
	public static void main(String args[]){
		//測試用例數目
		int N=6;	
		List<Integer> lis=new ArrayList<Integer>();	
		//添加測試用例1,2,3,4,5,6為序列
		for(int i=1;i<=N;i++){
			lis.add(i);
		}
		//輸出原測試用例序列
		System.out.println("測試用例序列:"+lis);
		//隨機排序
		Collections.shuffle(lis);
		System.out.println("隨機排序后測試用例序列:"+lis);		
	}
}

    結果顯示:

    

 

    2’·  貪心算法:

      一種能夠得到某種度量意義下的最優解的分級處理方法,它總是做出在當前看來是最優的選擇,也就是說貪心策略並不是從整體上加以考慮,它所做出的選擇只是在某種意義上的局部最優解算法。   

      該算法存在問題:
1. 不能保證求得的最后解是最佳的;
2. 不能用來求最大或最小解問題;
3. 只能求滿足某些約束條件的可行解的范圍。
      實現該算法的過程:
從問題的某一初始解出發;
while 能朝給定總目標前進一步 do
 求出可行解的一個解元素;
由所有解元素組合成問題的一個可行解;      

    

現在我用一個簡單的覆蓋矩陣進行代碼實現:

    首先我在F:\\目錄下創建了一個txt文件,文件名 greedyA.txt,內容如下:

    

    (橫向為四個測試用例,縱向為5個覆蓋語句,0為未覆蓋,1為已覆蓋)

    首先我們先整體上對排序的邏輯過程進行考量一下,先從F:\\greedyA.txt目錄下讀取文件,並置入數組,然后對每個測試用例進行相加,數字最大的為覆蓋范圍最大的,將此加入新的數組,並將該測試用例之和重置為-1,以此類推,直到序列排序完成。

    下面進行代碼實現:

package testpaixu;
import java.io.*;
import java.util.*;

//貪婪算法
public class greedyA {
	public static void main(String args[]){
		//test number
		int tn=4;
		String[] test=new String[tn];
		//下標為測試用例-1,數字為測試用例覆蓋范圍
		int[] sum=new int[tn];
		for(int i=0;i<sum.length;i++){
			sum[i]=0;		//初始化為0
		}
		
		//讀取測試用例覆蓋矩陣
		String filePath="F:\\greedyA.txt";

	        try {
	                String encoding="GBK";
	                File file=new File(filePath);
	                   //判斷文件是否存在
	                if(file.isFile() && file.exists()){ 
	                	//考慮到編碼格式
	                    InputStreamReader read = new InputStreamReader(	                   
	                    						new FileInputStream(file),encoding);	                   	                    
	                    BufferedReader br = new BufferedReader(read);	                    
	                    String lineTxt = null;
	                    
	                    System.out.println("測試用例覆蓋矩陣(橫向測試用例,縱向覆蓋語句(“0”未覆蓋,“1”已覆蓋)):");
	                    while((lineTxt =br.readLine()) != null){
	                    	//分解覆蓋矩陣
	                    	test=lineTxt.split(" ");	                    	
	                    	System.out.println(test[0]+test[1]+test[2]+test[3]);
	                    	//每個測試用例的覆蓋范圍
	                    	sum[0]=sum[0]+Integer.parseInt(test[0]);
	                    	sum[1]=sum[1]+Integer.parseInt(test[1]);
	                    	sum[2]=sum[2]+Integer.parseInt(test[2]);
	                    	sum[3]=sum[3]+Integer.parseInt(test[3]);	                    	
	                    }	
	                    read.close();
	        }else{
	            System.out.println("找不到指定的文件");
	        }
	        } catch (Exception e) {
	            System.out.println("讀取文件內容出錯");
	            e.printStackTrace();
	        }	 

	        System.out.println("測試用例1覆蓋范圍:"+sum[0]);
	        System.out.println("測試用例2覆蓋范圍:"+sum[1]);
	        System.out.println("測試用例3覆蓋范圍:"+sum[2]);
	        System.out.println("測試用例4覆蓋范圍:"+sum[3]);
	       	     
	        //使用貪婪算法對測試用例集排序
	        List<Integer> ls=new ArrayList<Integer>();	//初始化貪婪算法后序列
	        int[] tests=new int[tn];
	        for(int i=0;i<tests.length;i++){
	        	tests[i]=i+1;	//測試用例集初始序列
	        }
	        int index=0;
	        int max=sum[0];
	        
	        for(int j=0;j<sum.length;j++){
	        //獲取數組最大
	        for(int i=0;i<sum.length;i++){
	        	if(sum[i]>max){
	        		max=sum[i];
	        		index=i;
	        					}
	        }
	        ls.add(tests[index]);
	        sum[index]=-1;	
	        max=sum[index];
	        }	        
	        System.out.println("測試用例集排序后序列:	"+ls);	        
	}	       
}
			
	

    運行結果:

  

 

3‘  額外貪心:迭代的選取覆蓋實體最多的實例,然后對於剩下的測試用例調整覆蓋信息,把被選取的測試用例標記為“覆蓋的”,重復此過程直至測試實體集中所有的實例都被標記為“覆蓋的”。

  算法實現思想:對測試用例集的覆蓋與未覆蓋標記為“1”和“0”,獲取測試用例集原始序列,對各測試的分布進行相加,結果最大的編入結果序列list2。起始設定兩個序列list,一個全部為0記為slst,一個全部為1記為slst2。在求和獲得最大的測試進行修改,將此項為1的全部編入slst;然后將slst中為1的對應項對所有測試用例集的對應項修改,將他們全部改為0(以便循環相加求和時不會沖突),以此循環直到slst==slst2為true。

         到此,還有一步完善,將結果序列與原始序列相比較,先前未排序的加入到結果序列末端。

  下面進行編譯實現,同第二種算法一樣,先於extragreedyA.txt中添加一個覆蓋矩陣(橫向為測試用例序列,縱向為覆蓋語句序列),覆蓋矩陣如下:

  

  代碼實現如下:

package testpaixu;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;

//額外貪心算法
public class extragreedyA {
	public static void main(String args[]){
		//test number
		int tn=4;
		//覆蓋語句數量
		int sn=5;
		String[] test=new String[tn];
		//下標為測試用例-1,數字為測試用例覆蓋范圍
		int[] sum=new int[tn];
		for(int i=0;i<sum.length;i++){
			sum[i]=0;		//初始化為0
		}
		//測試用例的覆蓋語句分布
		ArrayList<Integer> lst1=new ArrayList<Integer>();
		ArrayList<Integer> lst2=new ArrayList<Integer>();
		ArrayList<Integer> lst3=new ArrayList<Integer>();
		ArrayList<Integer> lst4=new ArrayList<Integer>();
		List<ArrayList<Integer>> lst=new ArrayList<ArrayList<Integer>>();
		lst.add(lst1);
		lst.add(lst2);
		lst.add(lst3);
		lst.add(lst4);
		
		//初始化覆蓋均為0,及均未覆蓋
		ArrayList<Integer> slst=new ArrayList<Integer>();
		for(int i=0;i<sn;i++){
		slst.add(0);	}
		System.out.println("初始化語句均為未覆蓋:"+slst);
		//最后覆蓋語句均為1
		ArrayList<Integer> slst2=new ArrayList<Integer>();
		for(int i=0;i<sn;i++){
		slst2.add(1);	}

		
		//讀取測試用例覆蓋矩陣
		String filePath="F:\\extragreedyA.txt";

	        try {
	                String encoding="GBK";
	                File file=new File(filePath);
	                   //判斷文件是否存在
	                if(file.isFile() && file.exists()){ 
	                	//考慮到編碼格式
	                    InputStreamReader read = new InputStreamReader(	                   
	                    						new FileInputStream(file),encoding);	                   	                    
	                    BufferedReader br = new BufferedReader(read);	                    
	                    String lineTxt = null;
	                    
	                    System.out.println("測試用例覆蓋矩陣(橫向測試用例,縱向覆蓋語句(“0”未覆蓋,“1”已覆蓋)):");
	                    while((lineTxt =br.readLine()) != null){
	                    	//分解覆蓋矩陣
	                    	test=lineTxt.split(" ");	                    	
	                    	System.out.println(test[0]+test[1]+test[2]+test[3]);
	                    	//每個測試用例的覆蓋范圍
	                    	sum[0]=sum[0]+Integer.parseInt(test[0]);
	                    	sum[1]=sum[1]+Integer.parseInt(test[1]);
	                    	sum[2]=sum[2]+Integer.parseInt(test[2]);
	                    	sum[3]=sum[3]+Integer.parseInt(test[3]);	
	                    	//每個測試用例覆蓋語句分布	               
	                    	lst.get(0).add(Integer.parseInt(test[0]));
	                    	lst.get(1).add(Integer.parseInt(test[1]));
	                    	lst.get(2).add(Integer.parseInt(test[2]));
	                    	lst.get(3).add(Integer.parseInt(test[3]));
	                    }	
	                    read.close();
	        }else{
	            System.out.println("找不到指定的文件");
	        }
	        } catch (Exception e) {
	            System.out.println("讀取文件內容出錯");
	            e.printStackTrace();
	        }	
	        //測試用例覆蓋矩陣
	        for(int i=0;i<tn;i++){
	        	System.out.println("測試用例"+(i+1)+"覆蓋范圍:"+sum[i]+"分布:"+lst.get(i));
	        }

	       	     	        
	        //使用額外貪婪算法對測試用例集排序
	        ArrayList<Integer> ls=new ArrayList<Integer>();	//初始化貪婪算法后序列
	        int[] lstsum;
	        int add;
	        int index;
	        int max;
	        boolean b=true;
	        while(b){
	        	//獲得每個測試用例的覆蓋范圍
	        	add=0;
	        	lstsum=new int[tn];
	        	for(int m=0;m<lst.size();m++){
	    		for(int n=0;n<lst.get(m).size();n++){
	    			int j=(Integer)lst.get(m).get(n);
	    			add+=j;
	    									}
	    			lstsum[m]=add;
	    			add=0;
	        	}
	        	//獲取覆蓋范圍最大的測試用例
	        	index=0;
		        max=lstsum[0];
		        
		        //獲取數組最大
		        for(int i=0;i<lstsum.length;i++){
		        	if(lstsum[i]>max){
		        		max=lstsum[i];
		        		index=i;
		        				}
		        }		        
		        ls.add((index+1));
		        //將初始序列覆蓋范圍改掉
		        for(int i=0;i<slst.size();i++){
		        	if(lst.get(index).get(i)==1){		        		
		        		slst.set(i, 1);		       
		        	}
		        }		
		        //將該序列覆蓋的均改為0,並延至所有序列
		        for(int i=0;i<lst.size();i++){
		        	for(int j=0;j<lst.get(i).size();j++){
		        		if(slst.get(j)==1){
		        			lst.get(i).set(j, 0);
		        			
		        		}
		        	}
		        }	   
		        max=-1;
		        
		        for(int i=0;i<slst.size();i++){
		        	if(slst.get(i)!=slst2.get(i)){
		        		b=true;break;
		        	}
		        	b=false;
		        }	       	   	        
	        }	     	        
	        //如果排序后還有測試用例沒有排序,要對tests[]的剩余進行添加
	        ArrayList<Integer> tests=new ArrayList<Integer>();
	        for(int i=0;i<tn;i++){
	        	tests.add(i+1);
	        }
	        System.out.println("測試用例集排序前序列:	"+tests);
	        for(int i=0;i<tests.size();i++){
	        	if(!(ls.contains(tests.get(i)))){
	        		ls.add(tests.get(i));
	        	}
	        }
	        System.out.println("測試用例集排序后序列:	"+ls);
	       
	}	
}

    顯示結果:

    

總結:

   自動化測試的整體步驟如下(目標為一個程序a.java):

   1‘先是利用randoop工具對程序自動生成測試用例,得到測試用例集文件(tests.java文件),並撰寫生成報告(包含日期時間,原程序名稱,測試數量及概述,操作時間等);

   2’其次,對源程序進行插樁(利用Javassist進行方法,語句插樁)得到文件(a.class,與原a.class文件不同,目錄不在bin文件夾內);

   3’利用Java Runtime.exec()方法對測試用例集文件進行編譯得到tests.class文件。

    (該方法使用方法博客網址:  http://www.cnblogs.com/mingforyou/p/3551199.html )

   運行tests.class查看每個測試用例插樁結果:

      a  獲取覆蓋信息(覆蓋哪些語句,方法)並導入一個txt文件中方便查看、

      b  各個用例的覆蓋率(方便用貪心算法和隨機算法)、

      c  各個用例的覆蓋分布(覆蓋於未覆蓋),已覆蓋矩陣的形式導入txt文件中,以便運用額外貪心算法進行排序。

   並撰寫收集報告(包含日期時間,源程序名稱,測試用例集名稱,以及該集合的覆蓋率矩陣,操作時間等);

   4‘排序(三種算法),讀取上一個步驟形成的兩個txt文件,對覆蓋率或者覆蓋分布矩陣進行排序;

   5’收集排序結果,並撰寫排序報告(包含日期時間,源程序名稱,測試用例集名稱,排序實現程序名稱,測試用例集的覆蓋分布,測試用例集的結果序列等)。

   題外話,過此我每個流程都進行了粗糙的代碼實現,因此會對一個完整的程序進行完整的流程實現(自動生成測試用例,收集覆蓋矩陣,排序,排序結果輸出)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM