软件质量与测试--第二周作业 WordCount
GitHub: https://github.com/inverai/TestHome
PSP:
PSP2.1 | PSP 阶段 | 预估耗时 (分钟) | 实际耗时 (分钟) |
---|---|---|---|
Planning | 计划 | 25 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 25 | 20 |
Development | 开发 | 230 | 270 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 30 |
· Design Spec | · 生成设计文档 | 0 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 15 |
· Design | · 具体设计 | 30 | 35 |
· Coding | · 具体编码 |
120
|
130 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 40 |
Reporting | 报告 | 60 | 70 |
· Test Report | · 测试报告 | 10 | 10 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 | 50 |
|
合计 | 315 | 360 |
解题思路:
1. 了解JAVA命令行的使用与JAVAC的使用;(网上教程)
2. 考虑基本功能的实现;
基础:
<1.> 需要学习JAVA文件的操作和输入输出流的操作,(具体参考网上教程即可)
<2. > 需要 了解动态数组的基本操作和String类的基本方法;
功能:
<1.>C文件字符数统计,(需要考虑JAVA换行与否, JAVA换行字符为/n + /r 算作两个字符, 需要做处理)
<2.> 单词总数,(一行一行处理, 利用String类的split来划分出单词,进行统计即可)
<3.> 总行数, ( 按行读取时统计即可,可以按情况处理空行是否计算入内)
<4.> 是否输出到文本,(将处理结果格式化为字符串,利用ArrayList存储, 然后设置一个flag即可, 如果在命令行找到 -o参数则遍历打印ArrayList即可)
3. 扩展功能的实现:
基础:
<1. > File类的基本方法;
<2. > String类的方法;
<3.> HashMap的使用;
功能:
<1. >递归处理复合目录下符合条件文件; (解析输入路径,提取目录和 文件格式,然后匹配合适文件名, 再遍历处理即可)
<2.> 返回更复杂的数据统计(代码行、空行、注释行); (根据要求写出条件判断、然后统计即可);
<3.> 停用词表去除统计 ; (将停用词表放入HashMap,在统计单词的时候获取到停用词即不统计即可);
4. 高级功能:
基础:
<1.> Swing编程;
功能:
<1.> 通过图形界面选择文件输出统计信息; (使用JFrame 和 ActionListener 即可);
5. 测试功能:
<1.> 根据课程提供的测试用例来确认功能的基本实现;
<2.> 自己设计测试用例来测试细节实现;
6. 参数格式:
<1.> // Format: ----- "filename.c" -e "stop.txt" -o "func_output.txt"
<2.> // Format: ----- "filename.c" -o "func_output.txt"
<3.> // Format: ----- "filename.c" -e "stop.txt"
<4.> // Format: ---- "filename.c"
程序设计实现
1. 本程序主要包括一个Test类以及一个FileChooser类, 统计参数的存储全部使用 类的私有变量 HashMap来存储, 功能的实现通过函数来切分;
2. 基本结构:
3. 代码说明:
<1.> 初始化参数和功能的选择
public static void main(String[] args) throws Exception{ Test test = new Test(); String stop_name, filename, output_name; if(args[0].equals("-o") && args.length == 2) { throw new Exception("Illegal Parameters"); } for(int i = 0; i < args.length; i++) { test.map_inst.put(args[i], i); System.out.println(args[i]); } if(test.map_inst.get("-x") != null) { FileChooser chooser = new FileChooser(); filename = chooser.filepath; test.map_inst.put("-c" , 1); test.map_inst.put("-w" , 2); test.map_inst.put("-l" , 3); test.map_inst.put("-a" , 4); test.map_inst.put("-o" , 5); test.process(filename, "../stoplist.txt", "../output.txt"); } else { // get parameters // Format: ----- "filename.c" -e "stop.txt" -o "func_output.txt" if(test.map_inst.get("-e") != null && test.map_inst.get("-o") != null){ int pos = test.map_inst.get("-e"); stop_name = args[pos + 1]; filename = args[pos - 1]; output_name = args[pos + 3]; }else if(test.map_inst.get("-o") != null){ // Format: ----- "filename.c" -o "func_output.txt" stop_name = null; int cond = test.map_inst.get("-o"); output_name = args[cond + 1]; filename = args[cond - 1]; }else if(test.map_inst.get("-e") != null){ // Format: ----- "filename.c" -e "stop.txt" output_name = null; int pos = test.map_inst.get("-e"); stop_name = args[pos + 1]; filename = args[pos - 1]; }else { // Format: ---- "filename.c" filename = args[args.length - 1]; output_name = null; stop_name = null; } if(test.map_inst.get("-s") != null){ String dictName = args[args.length - 1]; int index = dictName.indexOf('*'); String dict = dictName.substring(0, index); String file_pattern = dictName.substring(index + 1); File file = new File(dict); if(file.exists()) { File files[] = file.listFiles(); for(File file1: files) { if(file1.getName().contains(file_pattern)) { test.process(file1.getAbsolutePath(), stop_name, output_name); } } } }else { test.process(filename, stop_name, output_name); } } }
<2.> 具体不同输出结果的获取
public void process(String filename, String stop_name, String output_name) throws Exception{ if(map_inst.get("-c") != null || map_inst.get("-w") != null || map_inst.get("-l") != null) { func_element(new BufferedReader(new InputStreamReader(new FileInputStream(filename)))); if(map_inst.get("-c") != null) list.add(filename + ", char count:" + map.get("count_char") + "\n"); if(map_inst.get("-w") != null) list.add(filename + ",word count:" + map.get("count_word") + "\n"); if(map_inst.get("-l") != null) list.add(filename + ",line count:" + map.get("count_line") + "\n"); } if(map_inst.get("-a") != null) { func_extend(new BufferedReader(new InputStreamReader(new FileInputStream(filename)))); list.add(filename + ",blank lines count:" + map.get("count_null") + "\n"); list.add(filename + ",Note lines count:" + map.get("count_note") + "\n"); list.add(filename + ",Code lines count:" + map.get("count_code") + "\n"); } if(map_inst.get("-e") != null) { BufferedReader stop = new BufferedReader(new InputStreamReader(new FileInputStream(stop_name))); String line = null; while((line = stop.readLine()) != null) { if (line.length() == 0) { continue; } String str[] = line.trim().split(" |,"); for(int j = 0; j < str.length; j++) { map_stop.put(str[j], 10); } } func_stop(new BufferedReader(new InputStreamReader(new FileInputStream(filename)))); list.add(filename + ",word count(stop_list):" + map.get("count_word_stop") + "\n"); } if(map_inst.get("-o") != null) { func_output(output_name); } }
<3.> 基本功能的实现
public void func_element(BufferedReader br) throws Exception{ int count_char = 0; int count_line = 0; int count_word = 0; String line = null; while((line = br.readLine()) != null) { if(line.length() == 0){ continue; } count_char += line.length(); count_word += line.trim().split(" |,").length; count_line++; } if(count_line == 1) { map.put("count_char", count_char); } else{ map.put("count_char", count_char - (count_line - 1) * 2); } map.put("count_line", count_line); map.put("count_word", count_word); }
<4.> 扩展功能的实现
public void func_extend(BufferedReader br) throws Exception{ int count_null = 0; int count_note = 0; int count_code = 0; boolean con_note = false; String line = null; while((line = br.readLine()) != null) { String trim = line.trim(); if(true == con_note && trim.charAt(0) == '*' && trim.charAt(1) == '/') { con_note = false; } if(con_note) { count_note++; } if(trim.length() <= 1){ count_null++; }else if(trim.charAt(0) == '/' && trim.charAt(1) == '/') { count_note++; }else if(trim.length() >= 3) { if(trim.charAt(0) == '}' && trim.charAt(1) == '/' && trim.charAt(2) == '/') { count_note++; } } else if(trim.charAt(0) == '/' && trim.charAt(1) == '*') { con_note = true; count_note++; } else { count_code++; } if(true == con_note && trim.charAt(trim.length() - 2) == '*' && trim.charAt(trim.length() - 1) == '/') { con_note = false; } } map.put("count_null", count_null); map.put("count_note", count_note); map.put("count_code", count_code); }
<5.> 高级功能的实现
if(test.map_inst.get("-x") != null) { FileChooser chooser = new FileChooser(); filename = chooser.filepath; test.map_inst.put("-c" , 1); test.map_inst.put("-w" , 2); test.map_inst.put("-l" , 3); test.map_inst.put("-a" , 4); test.map_inst.put("-o" , 5); test.process(filename, "../stoplist.txt", "../output.txt");
4. 测试过程
<1.> 在开发过程中根据老师提供的测试用例开发,全部通过;
<2.> 自己设计测试用例进行测试,将结果输出至output.txt;测试的高风险点包括代码中包含分支判定及循环的位置,在测试中采用的语句覆盖的方法覆盖到了所有程序代码语句,用以应对高风险点。
<3.> 个别测试样例:
(1) test.exe -w -c filename.c -o func_output.txt
(2) test.exe -w filename.c -e stop.txt
(3) test.exe -w -c filename.c
(4) test.exe -w -l -s filename.c -o func_output.txt
(5) test.exe -w -c -l -s filename.c -e stop.txt -o func_output.txt
测试样例通过测试。
5. 参考文献
https://www.cnblogs.com/jiqing9006/p/6231290.html JAVA文件操作与输入输出流
http://blog.csdn.net/chenqk_123/article/details/49304469 java指定目录下递归读取文件
https://www.cnblogs.com/dongrilaoxiao/p/6688107.html JAVABufferReader使用
https://www.cnblogs.com/panxuejun/p/5958875.html JAVA的HashMap使用