第二週做業:WordCount小程序的實現及測試

軟件質量與測試第二週做業WordCount小程序的實現及測試

github地址

  https://github.com/Asfalas/WordCounthtml

PSP

  

PSP2.1 PSP 階段 預估耗時 (分鐘) 實際耗時 (分鐘)
Planning 計劃 20 15
· Estimate · 估計這個任務須要多少時間 20 15
Development 開發 300 345
· Analysis · 需求分析 (包括學習新技術) 20 15
· Design Spec · 生成設計文檔 0 0
· Design Review · 設計複審 (和同事審覈設計文檔) 0 0
· Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 10 10
· Design · 具體設計 30 20
· Coding · 具體編碼 200 240
· Code Review · 代碼複審 10 10
· Test · 測試(自我測試,修改代碼,提交修改) 30 50
Reporting 報告 100 100
· Test Report · 測試報告 10 10
· Size Measurement · 計算工做量 10 5
· Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 80 85
  合計 420 460

解題思路

  審題之後大體思路以下:java

  一、資料能夠經過諸如百度、谷歌等搜索引擎獲取git

  二、程序能夠分爲:命令參數分析、輸入輸出文件定位、執行命令三個主體部分github

    (1)首先是命令參數分析部分,直觀的想法就是使用一個Vector<String>容器(Java Vector操做參見文後參考文獻)存儲命令參數,如:-c  -w  -l  -s  -a,另外後面需附加文件路徑的兩個命令:-o -e則直接進行分析處理再也不放入容器。正則表達式

    (2)輸入文件定位,若是命令參數容器中含有-s,則執行findFiles命令,遞歸(參見參考文獻)查找該目錄下全部的符號要求的文件並放入全局容器Vector<File>  sourcefile中,不然直接將輸入的單個文件放入容器中,至於輸出文件則直接複製給字符型變量outpath。小程序

    (3)命令執行模塊中,實現創建類WordCount,它的屬性用來存放一寫統計用的變量數值,它的方法即對應每一個命令參數的不一樣功能,構造方法中須要輸入輸入文件容器,輸出文件名,停用詞表文件名用以傳遞參數。執行count操做時,將源文件依次按行讀入字符串s,對於-c命令,直接統計每一行的s.length的加和便可;對於-w命令,可以使用String類的split方法使用正則表達式對改行進行分割,按要求分割出單詞並統計數量。對於-l命令,每存在一行則將行數加一便可。app

    (4)在主函數中一次對命令參數進行分析,定位輸入輸出文件並建立類WordCount的對象,最後調用該對象的方法進行響應的統計功能便可。函數

  三、測試,即單元測試,在Test類中對上述的各類方法執行測試,主要採用的方法爲語句覆蓋測試。對每一個方法採用2-3個用例對其進行測試。單元測試

程序設計實現

  本程序包含三個類:主函數類Main,統計類WordCount及測試類Test學習

  主函數類以下圖所示:包括主方法main,命令解析方法analysisInstructions,遞歸文件查找方法findFiles以及停用詞表文件查找方法findStopList。

  

 

   WordCount類中包括:各類屬性,構造方法WordCount,統計方法count,統計字符方法countChars,統計單詞方法countWords,統計行數方法countLines,初始化讀取文件方法initReadFile和釋放文件資源方法terminate,以下圖所示:

 

  測試類詳見下面的測試設計過程

  類及函數之間的調用流程以下:

     在主方法中調用analysisInstructions解析命令並在此過程當中按照須要調用findFiles及findStopList初始化全局變量,並傳入這些全局變量以初始化WordCount的對象wc,調用wc的count方法進行對應的統計功能。

代碼說明

  主函數:調用命令分析函數並初始化類WordCount的對象wc,再調用其count方法。

 1     public static void main(String[] args) {  2  analysisInstructions(args);  3         if (sourcefile.isEmpty()) {  4             System.out.println("請輸入要統計的文件路徑名");  5             return;  6  }  7         try{  8             WordCount wc = new WordCount(sourcefile, outpath, stoplist);  9  wc.count(instructions); 10  } 11         catch(IOException e){ 12             System.out.println("找不到輸入文件或目錄"); 13             return; 14  } 15         return; 16     }

  命令分析函數:包含對args[]參數的各個元素進行檢查並執行對應的操做,變量使用全局變量的形式存儲,所以函數返回值爲void。

 1 public static void analysisInstructions(String[] args) {  2         File directory = new File("");  3         path = directory.getAbsolutePath()+"\\";//獲取絕對路徑
 4         instructions = new Vector<String>();  5         stoplist = new Vector<String>();  6         sourcefile = new Vector<File>();  7         outpath = "result.txt";  8         boolean flag = false;  9         for (int i = 0; i < args.length; i++) { 10             if (args[i].equals("-o")) { 11                 if (++i == args.length) { 12                     System.out.println("請輸入輸出文件路徑名"); 13                     return; 14  } 15                 outpath = args[i]; 16  } 17             else if (args[i].equals("-c") || args[i].equals("-w") || args[i].equals("-l")|| args[i].equals("-a")) 18  instructions.addElement(args[i]); 19             else if (args[i].equals("-e")) { 20                 if (++i == args.length) { 21                     System.out.println("請輸入停用文件路徑名"); 22                     return; 23  } 24                 try {findStopList(args[i]);} 25                 catch (IOException e){ 26                     System.out.println("找不到停用詞文件"); 27                     return; 28  } 29  } 30             else if (args[i].equals("-s")) 31                 flag = true; 32             else { 33                 if (!flag) 34                     sourcefile.addElement(new File(args[i])); 35                 else { 36                     String filter = args[i].substring(args[i].indexOf(".")); 37  System.out.println(filter); 38                     if(args[i].indexOf("*") == 0) 39  findFiles(path, filter); 40                     else
41                         findFiles(args[i].substring(0,args[i].indexOf("*")),filter); 42  } 43  } 44  } 45     }

 

  WordCount類的count方法:流程爲依次讀取源文件,並逐個按照命令容器中存在的命令進行處理。

 1     public void count(Vector<String> instructions) throws IOException {  2         for (int i = 0; i < sourcepath.size(); i++) {  3  initReadFile(i);  4             if (instructions.contains("-c"))  5  countChars(i);  6             if (instructions.contains("-w"))  7  countWords(i);  8             if (instructions.contains("-l"))  9  countLines(i); 10             if (instructions.contains("-a")) 11  countOther(i); 12  } 13  terminate(); 14     }

  下面以countWords爲例展現統計源代碼:逐行讀入源文件,去除空行後,使用split方法對用空格,逗號,換行符分割的字符串進行分割,而後再判斷是否同停用詞表中的一致,再統計單詞數。

 1     public String countWords(int index) throws IOException {  2  initReadFile(index);  3  String s;  4         wordNum = 0;  5         while ((s = br.readLine()) != null) {  6             if (Pattern.matches("\\s*", s))  7                 continue;  8             String[] words = s.split(" |,|\\t");  9             for (String l : words) 10                 if (!stoplist.contains(l.toLowerCase()) && !Pattern.matches("\\s*",l)) 11                     wordNum++; 12  } 13         String result = sourcepath.get(index).getAbsolutePath().substring(path.length()) 14                 + ", 單詞數: " + String.valueOf(wordNum) + "\r\n"; 15         byte[] data = result.getBytes(); 16  output.write(data); 17         return result; 18     }

  其他統計方法思路相似,在此不一 一展現,詳情請在github中查看源代碼。

測試設計過程

  在test類中編寫單元測試,對本項目中的主要函數方法進行單元測試,主要採起語句覆蓋測試方法。

  測試1:測試analysisInstructions方法,輸入"-c -l -w -a testcase.c -o 1.txt"後主類中的全局變量是否符合預期。

 1  //測試輸入參數的解析方法
 2     public static boolean testAnalysisInstructions() {  3         //用例1:語句覆蓋測試
 4         String[] test = {"-c", "-l", "-w", "-a", "testcase.c", "-o", "1.txt"};  5  Main.analysisInstructions(test);  6         if (Main.sourcefile.size() == 1 && Main.sourcefile.get(0).getName().equals("testcase.c"))  7             if (Main.stoplist.isEmpty())  8                 if (Main.outpath.equals("1.txt"))  9                     if (Main.instructions.contains("-c") &&
10                             Main.instructions.contains("-w") &&
11                             Main.instructions.contains("-l") &&
12                             Main.instructions.contains("-a")) 13                         return true; 14         return false; 15     }

  測試二、三、4:對findStopList方法進行測試,針對三種狀況進行測試,覆蓋邊界,具體參見代碼註釋。stopList文件中含有{「apple」,「banana」,「pie」}三個停用詞。

 1  public static boolean testFindStopList() {  2         try {  3             //用例2:stoplist文件中含有字符
 4             Main.stoplist = new Vector<String>();  5             Main.findStopList("testcase\\stoplist.txt");  6             if (!(Main.stoplist.contains("apple") && Main.stoplist.contains("banana")  7                     && Main.stoplist.contains("pie")))  8                 return false;  9             //用例3:stoplist文件爲空
10             Main.stoplist = new Vector<String>(); 11             Main.findStopList("testcase\\stoplist1.txt"); 12             if (!Main.stoplist.isEmpty()) 13                 return false; 14             //用例4:stoplist文件中僅含有空格等格式控制字符
15             Main.stoplist = new Vector<String>(); 16             Main.findStopList(("testcase\\stoplist2.txt")); 17             if(!Main.stoplist.isEmpty()) 18                 return false; 19         } catch (IOException E) { 20             return false; 21  } 22         return true; 23     }

  測試五、六、7:測試主類的findFiles方法,針對路徑下含有遞歸的文件夾,不含有遞歸的文件夾以及路徑中無符合要求的文件進行測試,即語句覆蓋。

 1     //測試查找文件方法()
 2     public static boolean testFindFiles() {  3         //用例5:路徑下無遞歸文件夾
 4         Main.sourcefile = new Vector<>();  5         Main.findFiles("./testcase/test", ".c");  6         if (!(Main.sourcefile.size() == 1 && Main.sourcefile.get(0).getName().equals("testcase1.c")))  7             return false;  8 
 9         //用例6:路徑下有遞歸文件夾
10         Main.sourcefile = new Vector<>(); 11         Main.findFiles("./", ".c"); 12         for (File f : Main.sourcefile) { 13             if (f.getName().equals("testcase.c") || f.getName().equals("test.c")||
14                     f.getName().equals("testcase1.c") || f.getName().equals("testcase2.c")) 15                 continue; 16             else
17                 return false; 18  } 19 
20         //用例7:無符合要求文件測試
21         Main.sourcefile = new Vector<>(); 22         Main.findFiles("./", ".none"); 23         if (!Main.sourcefile.isEmpty()) 24             return false; 25         return true; 26     }

  測試八、九、10:測試方法以下,輸入文件容器以及預期的標準輸出文件,則該方法會自動執行並將結果與輸入的標準對比,若相同則返回true,不然返回false。爲保證測試覆蓋度,默認命令容器中含有全部的命令參數。

 1     public static boolean testCount(Vector<File> source, String standardresult) {  2         Vector<File> sourcefile = source;  3         String outpath = "1.txt";  4         try {  5             Main.findStopList("./testcase/stoplist.txt");  6             Vector<String> stoplist = Main.stoplist;  7             WordCount wc = new WordCount(sourcefile, outpath, stoplist);  8             String[] ins = {"-c", "-w", "-l", "-a"};  9             Vector<String> instructions = new Vector<>(); 10             for (String i : ins) 11  instructions.addElement(i); 12  wc.count(instructions); 13             InputStreamReader isr = new InputStreamReader( 14                     new FileInputStream(new File("./1.txt"))); 15             BufferedReader result = new BufferedReader(isr); 16             InputStreamReader isr1 = new InputStreamReader( 17                     new FileInputStream(new File(standardresult))); 18             BufferedReader standard = new BufferedReader(isr1); 19  String std, rs; 20             while ((rs = result.readLine()) != null) { 21                 if ((std = standard.readLine()) == null) 22                     return false; 23                 if (!rs.equals(std)) 24                     return false; 25  } 26             if ((std = standard.readLine()) != null) 27                 return false; 28         } catch (IOException e) { 29             return false; 30  } 31         return true; 32  } 33 }

  對該測試的調用以下:

1         source.addElement(new File("testcase/testcase.c")); 2         System.out.println(testCount(source, "./testcase/testresult.txt"));//用例8:僅有一個文件統計測試
3         source.addElement(new File("testcase/test/testcase1.c")); 4         System.out.println(testCount(source, "./testcase/testresult1.txt"));//用例9:含有遞歸文件夾的統計測試
5  source.clear(); 6         source.addElement(new File("testcase/testcase2.c")); 7         System.out.println(testCount(source, "./testcase/testresult2.txt"));//用例10:空文件的統計測試

用例詳情以及標準輸出文件參見github項目路徑下的testcase文件夾。

測試結果以下:

  

  其他測試採用的老師在新發布的博客的樣例,全部用例均能經過。測試的高風險點包括代碼中包含分支斷定及循環的位置,在測試中採用的語句覆蓋的方法覆蓋到了全部程序代碼語句,用以應對高風險點。

參考文獻

  http://blog.csdn.net/ycy0706/article/details/45457311   java統計一個文件字符數,單詞數等的一個小示例

  https://www.cnblogs.com/zhaoyan001/p/6077492.html   java vector使用教程

  https://www.cnblogs.com/StanLong/p/6414383.html   java輸出文件到本地

  http://blog.csdn.net/chenqk_123/article/details/49304469   java指定目錄下遞歸讀取文件

相關文章
相關標籤/搜索