软件质量与测试 第二周作业 WordCount
Github地址:
https://github.com/Hu-Peking/WordCount
PSP2.1:
PSP 2.1 | PSP 阶段 | 预估耗时 (分钟) | 实际耗时 (分钟) |
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 300 | 540 |
· Analysis | · 需求分析(包括学习新技术) | 80 | 120 |
· Design Spec | · 生成设计文档 | 10 | 10 |
· Design Review | · 设计复审(和同事审核设计文档) | 10 | 10 |
· Coding Standard | · 代码规范(为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 10 | 40 |
· Coding | · 具体编码 | 130 | 300 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 70 | 120 |
· Test Report | · 测试报告 | 40 | 60 |
· Size Measurement | · 计算工作量 | 10 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结,并提出过程改进设计 | 20 | 40 |
合计 | 400 | 690 |
解题思路:
1、将程序的功能需求分为基础功能和拓展功能,按先后顺序分别实现两部分的内容;
2、先在IDE中实现对电脑中指定目录下的文件的读写操作;
3、编写程序,实现可以在Main函数的调用下分别正确运行各个基础功能;
4、编写程序,实现在终端执行该程序时,程序可以获取到终端输入的全部参数,并能对终端所在的目录下的文档进行读写;
5、调整Main函数中对各个功能的调用机制,使得在终端输入相应的参数时,程序可以正常执行所对应的功能;
6、确定程序可以正确运行所有的基础功能后,把工程打包成.jar文件,再将.jar文件转换成.exe文件,在终端中运行.exe文件,确保.exe可以正确执行所有基础功能;
7、基于实现基础功能的程序,进行扩展功能的程序的编写,完成所有的扩展功能;
8、确定程序可以正确运行所有功能后,把工程打包成.jar文件,再将.jar文件转换成.exe文件,在终端中运行.exe文件,确保.exe可以正确执行所有功能;
本工程的参考资料都是通过百度所查找的,均是博客
查阅资料:
http://blog.csdn.net/u012325167/article/details/50856515
http://blog.csdn.net/chengzhaoan2010/article/details/78344791
程序设计实现过程:
程序包含三个类,分别为Main、Action、Count和FileUtils
Main:程序的主函数类,实现整个程序的所有功能的调用,其中含有以下方法:
main():作为主方法。
Action:实现要执行功能的判断、各种统计功能的调用和最后的信息输出的功能,其中含有以下方法:
judges(String[] commands):命令分析函数,对终端中传入的参数进行判断,统计需要执行的功能;
do_thing(String[] orders):对需要执行的功能进行调用;
write(String[] write_content):对write_content中的内容进行打印;
Count:此类为本工程的主体,完成了-c, -w, -l, -o, -a, -e这些功能的实现,其中含有以下方法:
c(File file):统计文件中的字符数;
w(File file):统计文件的单词数;
l(File file):统计文件的行数;
a(File file):统计文件的代码行、空行和注释行的行数;
we(File file, File stop):统计文件中除去停用词表中的停用词后,剩余的单词总数;
FileUtils:此类实现了递归处理目录下符合条件的文件,其中含有以下方法:
getFiles(File dir):递归处理dir目录下的所有文件,对以.c结尾的文件进行命令行中的操作;
代码说明:
主函数:建立Action类的实例ac,通过ac调用Action中的命令分析、结果打印和功能调用这些方法;
1 public static void main(String[] args) { 2
3 String[] commands = new String[10]; 4 String print_content = null; 5 String[] lastone = new String[2]; 6
7 Action ac = new Action(); 8
9 commands = ac.judges(args); 10
11 if (commands[6].equals("true") && commands[7].endsWith(".c")) { 12 FileUtils fu = new FileUtils(commands); 13 print_content = fu.all_content; 14 } else { 15 print_content = Action.do_thing(commands); 16 } 17
18
19 lastone[0] = commands[8]; 20 lastone[1] = print_content; 21
22 ac.write(lastone); 23
24 }
命令分析函数:对args[]字符串数组中的参数进行判断,依次获取args[]中的每一个参数并将其与"-c", "-w", "-l", "-o", "-a", "-e", "-s"这7个字符串进行比较,决定程序需要对文件执行-c, -w, -l, -o, -a, -e, -s中的哪些功能;此外通过判断args[]中是否存在相等的字符串判断命令行输入是否有误,选取以".txt"和".c"结尾的,获取.c和.txt文件的文件名,最终将判断后所得的结果返回;
1 public String[] judges(String[] commands) { 2
3 String[] output = new String[10]; 4
5 // ArrayList<Object> output = new ArrayList<Object>();
6
7 boolean error = false; 8 boolean l = false; //1
9 boolean w = false; //2
10 boolean c = false; //3
11 boolean o = false; //4
12 boolean a = false; //5
13 boolean e = false; //6
14 boolean s = false; //7
15
16 String in_file = null; //8
17 String out_file = null; //9
18 String stop_file = null; //10
19
20 String path = null; 21
22 //保证输入的参数无重复
23 for (int i = 0; i < commands.length - 1; i++) { 24 for (int j = i + 1; j < commands.length; j++) { 25 if (commands[i].equals(commands[j])) { 26 error = true; 27 break; 28 } 29 } 30 if (error) { 31 break; 32 } 33 } 34
35 if (!error) { 36 for (int i = 0; i < commands.length; i++) { 37 if (commands[i].equals("-l")) { 38 l = true; 39 } else if (commands[i].equals("-w")) { 40 w = true; 41 } else if (commands[i].equals("-c")) { 42 c = true; 43 } else if (commands[i].equals("-a")) { 44 a = true; 45 } else if (commands[i].equals("-e")) { 46 e = true; 47 i = i + 1; 48 stop_file = commands[i]; 49 if (!stop_file.contains(".txt")) { 50 error = true; 51 break; 52 } 53 } else if (commands[i].equals("-o")) { 54 o = true; 55 i = i + 1; 56 out_file = commands[i]; 57 if (!out_file.endsWith(".txt")) { 58 error = true; 59 break; 60 } 61 } else if (commands[i].equals("-s")) { 62 s = true; 63 } else if (commands[i].endsWith(".c")) { 64 in_file = commands[i]; 65 } else { 66 error = true; 67 break; 68 } 69 } 70
71
72 File directory = new File(""); 73 try { 74 path = directory.getAbsolutePath(); 75 } catch (Exception e1) { 76 e1.printStackTrace(); 77 } 78
79
80 //确定要写的文件
81 if (!o) { 82 out_file = "result.txt"; 83 } 84
85
86 //确定停用词文件
87 File file_stop = null; 88 if (e) { 89 //设置停用词表
90 file_stop = new File(path + "/" + stop_file); 91
92 if (!file_stop.exists()) { 93 error = true; 94 System.out.println("停用词表不存在!"); 95 System.exit(0); 96 } 97 } 98
99 if (l) { 100 output[0] = "true"; 101 } else { 102 output[0] = "false"; 103 } 104
105 if (w) { 106 output[1] = "true"; 107 } else { 108 output[1] = "false"; 109 } 110
111 if (c) { 112 output[2] = "true"; 113 } else { 114 output[2] = "false"; 115 } 116
117 if (o) { 118 output[3] = "true"; 119 } else { 120 output[3] = "false"; 121 } 122
123 if (a) { 124 output[4] = "true"; 125 } else { 126 output[4] = "false"; 127 } 128
129 if (e) { 130 output[5] = "true"; 131 } else { 132 output[5] = "false"; 133 } 134
135 if (s) { 136 output[6] = "true"; 137 } else { 138 output[6] = "false"; 139 } 140
141 output[7] = path + "/" + in_file; 142 output[8] = path + "/" + out_file; 143 output[9] = path + "/" + stop_file; 144
145
146 } else { 147 System.out.println("命令行输入有误!"); 148 System.exit(0); 149 } 150 return output; 151 }
结果输出函数:在调用该函数时获取要打印到.txt文件中的内容,通过java.IO.File类的方法将结果打印到.txt文件中;
1 public void write(String[] write_content) { 2
3 //write_content[0] file write_content[1] content 4
5 //向文件中写入内容
6
7 File write_file = new File(write_content[0]); 8
9 if (!write_file.exists()) { 10 try { 11 write_file.createNewFile(); 12 } catch (Exception e1) { 13 e1.printStackTrace(); 14 } 15 } 16 try { 17
18 FileWriter fw = new FileWriter(write_file); 19 BufferedWriter bufw = new BufferedWriter(fw); 20 bufw.write(write_content[1]); 21 bufw.close(); 22 fw.close(); 23 } catch (Exception e1) { 24 e1.printStackTrace(); 25 } 26 System.out.println("Succeed!"); 27 }
递归处理函数:实现-s操作,以wc.exe所在的文件夹为起点,利用深度优先搜索,遍历wc.exe文件夹所在的目录下所有后缀名为.c的文件,并对这些文件依次进行命令行所输入的操作,具体操作如下:
1、遍历wc.exe所在的文件夹中的每个文件,判断其是否为文件或是文件夹;
2、若为文件则对其进行命令行所输入的操作;
3、若为文件夹则获取其中所有文件,并对每一个文件进行1中操作;
1 public void getFiles(File dir) { 2 if (dir.exists()) { 3 //判断是否是目录
4 if (dir.isDirectory()) { 5 File[] files = dir.listFiles(); 6
7 for (File file : files) { 8 getFiles(file); 9 } 10 } else { 11 String inFile = dir.getAbsolutePath(); 12 if (inFile.endsWith(".c")) { 13 arg[7] = inFile; 14 all_content = all_content + Action.do_thing(arg) + "\n"; 15 System.out.print("\n"); 16 } 17 } 18 } 19 }
-c, -w, -l, -o, -a, -e等的操作较为雷同,故选取-w所对应的函数进行举例;
单词统计:实现-w的操作,先获取读入文件的所有内容,再调用split()函数在" "和","处对所有内容进行分割,最后统计分割得到的字符串数组的长度,即为该文件中的单词数;
1 public int w(File file) { 2 //单词数
3 int word_num = 0; 4
5 //文本的全部内容
6 String content = ""; 7
8 //file存在,读取内容
9 if (file.exists()) { 10 try { 11 FileReader fr = new FileReader(file); 12
13 BufferedReader bufr = new BufferedReader(fr); 14 String s = null; 15
16 //获取文本全部内容
17 while ((s = bufr.readLine()) != null) { 18 content = content + s; 19 } 20 bufr.close(); 21 fr.close(); 22
23 String[] words = content.split("[ ]+|[,]+"); 24 /*for (int i = 0; i < words.length; i++) { 25 System.out.println(i + words[i]); 26 }*/
27 //获取单词数
28 word_num = words.length; 29 // System.out.println(word_num);
30 System.out.println(file.getName() + ",单词数:" + word_num); 31 } catch (Exception e1) { 32 e1.printStackTrace(); 33 } 34 } else { 35 word_num = -1; 36 System.out.println("文件不存在!"); 37 } 38 return word_num; 39 }
测试设计过程:
测试中本着用例覆盖所有分支的目的进行设计
测试用例如下所示:
1 //下面测试-c字符统计功能
2 if while else end 3
4
5 //下面测试-w的单词统计功能
6 interest ing 7 interest 8 ing 9
10
11 //下面测试-a的空行/代码行/注释行的统计功能 12 //空行测试
13
14 } 15 t 16
17 //代码行测试
18 if(){ 19 } else if(){ 20 } else{ 21 } 22
23 //注释行测试
24 s//
25 //
26 //
27
28
29 //下面测试-e的排除停用词表中单词的统计功能
30 typedef struct { 31 int startvex; 32 int endvex; 33 int length; 34 } edge; 35 edge T[M]; 36
37 void main() { 38 int dist[N][N] = {{0, 6, MAX, 7, MAX}, 39 {MAX, 0, 5, 8, -4}, 40 {MAX, -2, 0, MAX, MAX}, 41 {MAX, MAX, -3, 0, 9}, 42 {2, MAX, 7, MAX, 0}};//图的邻接矩阵
43 int d[N]; 44 int num = 0; 45 num = BellmanFord(dist, d, 0);//计算下标为0的顶点到其它顶点的距离,num用于统计边数
46 for (int i = 0; i < N; i++)//打印到各个顶点之间的距离
47 printf("%d ", d[i]); 48 printf("\n"); 49 for (int j = 0; j < num; j++)//打印考虑过的边
50 printf("start=%d,end=%d,lenth=%d\n", T[j].startvex, T[j].endvex, T[j].length); 51 }
终端命令行输入:
1 //单个功能测试 2 wc.exe -l file.c 3 wc.exe -c file.c 4 wc.exe -w file.c 5 wc.exe -a file.c 6 wc.exe -o out.txt 7
8 //组合功能测试 9 wc.exe -l -c file.c 10 wc.exe -l -w file.c 11 wc.exe -l -a file.c 12 wc.exe -c -w file.c 13 wc.exe -c -a file.c 14 wc.exe -w -a file.c 15
16 wc.exe -l -w file.c -e stop.txt 17 wc.exe -c -w file.c -e stop.txt 18 wc.exe -w -a file.c -e stop.txt 19
20 wc.exe -l -c -w -a file.c -e stop.txt 21
22 wc.exe -l -c -w -a file.c -e stop.txt -o out.txt 23
24 wc.exe -l -c -w -a -s *.c -e stop.txt 25 wc.exe -l -c -w -a -s *.c -e stop.txt -o out.txt 26
27
28 //错误测试 29 //无读取的文件 30 wc.exe -l -c 31 wc.exe -l -w 32 wc.exe -l -a 33 wc.exe -c -w 34 wc.exe -c -a 35 wc.exe -w -a 36
37 //有-e,但无停用词表文件名 38 wc.exe -l -w file.c -e 39 wc.exe -c -w file.c -e 40 wc.exe -w -a file.c -e 41
42 //有-o,但无输出文件名 43 wc.exe -l -c -w -a file.c -e stop.txt -o 44 wc.exe -l -c -w -a -s *.c -e stop.txt -o 45
46 //有-s,但无"*.c"
47 wc.exe -l -c -w -a -s -e stop.txt 48 wc.exe -l -c -w -a -s -e stop.txt -o out.txt
在终端中输入上述测试命令后,程序可以正常运行,且按我自己对需求的理解,运行输出均无误。
此外,在BIN文件夹中加入了.bat的测试脚本文件,双击他运行,通过对控制台的输出的对比,也可进行测试。
参考文献链接:
Git教程 - 廖雪峰的官方网站
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
java获取当前路径的几种方法 - CSDN博客
http://blog.csdn.net/chengzhaoan2010/article/details/78344791
java.io.File类基本使用——遍历某路径的所有文件夹及文件 - CSDN博客
http://blog.csdn.net/u012325167/article/details/50856515
手把手教你如何把java代码,打包成jar文件以及转换为exe可执行文件 - CSDN博客