第二周做业: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指定目录下递归读取文件

相关文章
相关标签/搜索