github地址
PSP表格
PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 10 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 15 |
Development | 开发 | 500 | 480 |
· Analysis | · 需求分析 (包括学习新技术) | 80 | 100 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 40 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 10 |
· Design | · 具体设计 | 60 | 55 |
· Coding | · 具体编码 | 450 | 460 |
· Code Review | · 代码复审 | 60 | 120 |
· Test | · 测试(自我测试,修改代码,提交修改) | 150 | 200 |
Reporting | 报告 | 100 | 120 |
· Test Report | · 测试报告 | 50 | 50 |
· Size Measurement | · 计算工作量 | 10 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 30 |
| 合计 | 1565 | 1750 |
接口设计
经由团队讨论,本次实验分为四个模块,分别为输入检测,单词检测及统计,单词排序,文本输出。我负责的模块为单词检测及统计。该接口返回一个map实体,接受一个文件路径参数。核心思路,提取文件中所有满足单词格式的字符串,并保存到一个String数组中,遍历该数组统计词频并保存结果到一个map实体中,返回该map实体。
代码如下:
public static Map<String, Integer> scan(String path)throws IOException { //读取文档并将所有单词放入list并统计 InputStreamReader isr = new InputStreamReader(new FileInputStream(path)); BufferedReader br = new BufferedReader(isr); String str=null; List<String> lists = new ArrayList<String>(); //存储过滤后单词的列表 while((str=br.readLine())!=null){ // String[] tmp= str.split(" |,|'"); String[] tmp = str.split("[^a-zA-Z-]"); //过滤出只含有字母的 for(int i=0;i<tmp.length;i++){ if(tmp[i].length()!=0) { //最后带短横线的但未链接的单词去掉短线 if((tmp[i].substring(tmp[i].length()-1, tmp[i].length())).equals("-")) { if(tmp[i].length()!=1)//避免单个横线时输出空字符 { lists.add(tmp[i].substring(0, tmp[i].length()-1)); //System.out.println(tmp[i].substring(0, tmp[i].length()-1)); } } //第一个带短横线的但未链接的单词去掉短线 else if((tmp[i].substring(0,1)).equals("-")) { if(tmp[i].length()!=1)//避免单个横线时输出空字符 { lists.add(tmp[i].substring(1, tmp[i].length())); } } else { lists.add(tmp[i]); //System.out.println(tmp[i]); } } } } isr.close(); Map<String, Integer> wordsCount = new TreeMap<String,Integer>(); //存储单词计数信息,key值为单词,value为单词数 //单词的词频统计 for (String li : lists) { if(wordsCount.get(li) != null){ wordsCount.put(li,wordsCount.get(li) + 1); }else{ wordsCount.put(li,1); } } return wordsCount; }
测试设计过程
测试用例的设计首先根据需求来设计,单词及词频统计模块主要根据单词判定的边界来设计,主要测试边界是一些特殊字符,和判定条件。为了保证该模块的正确性,分别采取了白盒测试、黑盒测试,并在黑盒测试的基础上进行了压力测试。
Test Case ID 测试用例编号 | Test Item 测试项 (功能模块或函数) | Test Criticality 重要级别 | Pre-condition 预置条件 | Input 输入 | Procedure 操作步骤 | Output 预期结果 | Result | Status | Remark 备注 (在此描述使用的测试方法) |
testScan1 | Scan | L | 无 | 待测文件路径 | 无 | true | true | Y | 白盒测试 |
testScan2 | L | 无 | 无 | true | true | Y | |||
testScan3 | M | 无 | 无 | true | true | Y | |||
testScan4 | L | 无 | 无 | true | true | Y | |||
testScan5 | L | 无 | 无 | true | true | Y | |||
testScan6 | L | 无 | 无 | true | true | Y | |||
testScan7 | M | 无 | 无 | true | true | Y | |||
testScan8 | M | 无 | 无 | true | true | Y | |||
testScan9 | M | 无 | 无 | true | true | Y | |||
testScan10 | L | 无 | 无 | true | true | Y | |||
testScan11 | H | 无 | 无 | true | true | Y | 黑盒测试 | ||
testScan12 | H | 无 | 无 | true | true | Y | |||
testScan13 | H | 无 | 无 | true | true | Y | |||
testScan14 | L | 无 | 无 | true | true | Y | |||
testScan15 | M | 无 | 无 | true | true | Y | |||
testScan16 | L | 无 | 无 | true | true | Y | |||
testScan17 | M | 无 | 无 | true | true | Y | |||
testScan18 | H | 无 | 无 | true | true | Y | |||
testScan19 | H | 无 | 无 | true | true | Y | |||
testScan20 | H | 无 | 无 | true | true | Y | |||
testScan21 | M | 无 | 无 | true | true | Y | 黑盒测试 (压力测试) | ||
testScan22 | M | 无 | 无 | true | True | Y |
测试用例描述:
1.testScan1--testScan5:分别是对大写字母组成的单词、小写字母组成的单词、大小写字母混合组成的单词、以“-”开头的单词、以“-”结尾的单词的测试。数据量小,目的为判断程序路径的正确性;
2.testScan6--testScan10:分别是对不含有大写字母组成的单词的测试文本文件、不含有小写字母组成的单词的测试文本文件、不含有大小写字母混合组成的单词的测试文本文件、不含有以“-”开头的单词的测试文本文件、不含有以“-”结尾的单词的测试文本文件的测试;其中对单词数目的计数测试也放在这五个测试用例中,在一个测试文本文件中,单词数目被设为一个或多个。数据量小;
3.testScan11--testScan18:分别是从网上随机选取的格式规范的单词集合。数据量小;
4.testScan19--testScan20:这两个测试用例,采用胡乱输入的方式(类似一巴掌拍在键盘上)获得的测试用例,用于对于不合常理的输入的正确性测试。数据量小;
5.testScan21--testScan20:测试用例中包含大量符合单词格式的单词。数据量大。
单元测试截图
单元测试分别进行了白盒测试、黑盒测试和压力测试:
1-10:白盒测试,根据路径覆盖设计的测试用例;
11-20:黑盒测试,利用随机选取的单词组,以及手动随机输入字符的形式来获取测试用例;
21-22:压力测试,测试用例中包含大量单词,以千记位,此时代码的执行效率收到明显影响。对比测试21和22,尤其是当文件中包含有大量不常用字符时,代码效率下降跟为明显。
开发规范说明
选择的是Google Java编程风格指南
中文版链接:https://blog.csdn.net/zen99t/article/details/50763231
代码分析
评审的是SortMap(输出排序)模块的代码,该代码基本符合编程规范。其中有所不符合的是:
1. import后不要使用通配符;
2. 大括号的使用,即使只有一条语句(或是空),也应该把大括号写上;
3. 块缩进,两个空格。部分缩进未达到要求。
命名规范方面,该模块与规范一致,类名都以UpperCamelCase风格编写,方法名都以lowerCamelCase风格编写,参数名以lowerCamelCase风格编写,未出现单词缩写等。
静态代码检查工具
采用了多种工具,并比对发现各种工具的检测规则不尽相同。
有PMD,findbugs,checkstyle,所需插件均能在该站点找到:http://sourceforge.net/
工具扫描结果
PMD和findbugs扫描结果都为无错误,选用其他代码进行展示错误结果。
PMD:
FindBugs:
Checkstyle:
Checkstyle规范较为严格,对缩进空格有着严格的规定,导致所有代码都不符合规范,而findbugs和PMD则发现不了问题。本次实验代码还是较为符合编程规范的。其遵循的好的规范主要都在Google Java编程风格指南中可以找到。
小组代码分析
本次小组实验的代码基本还是比较符合规范的,本次小组实验的代码基本还是比较符合规范的,但是整合过程出现了些小纰漏,与前期商讨不足不无关系。其次,就是模块划分的不够严谨,注释方面不够详尽,部分模块的代码可读性不够高。
数据集的设计思路
为了给程序带来压力,需要构建一个数据量足够大的txt文档,其中单词需要足够的多,不仅如此,为了能够给代码带来足够的考验,单词的种类也需要不同,即要有很多不同的单词,此时可以找到多篇英文文章连在一起即可。最后采用的txt文档总行数为3126行,单元数有785128个,此时的数据量已经足够大了。
性能指标
采用的性能指标为时间的长短。
数据加倍之后:
可以发现程序的效率还是非常高的。
同行评审
全部组员都参加了同行评审,由组长进行主持,主要评审的模块是scan和sort模块,由于这两个模块消耗资源较多,所以需要进行评审改进。通过对实验需求的研究和模块效率的实验,最终评审的结论为,由于这两个模块采用的函数都是使用的Java内置函数来解决,如split(),map数组的排序等,所以效率应该最大化,不需要太大的改进。
测试结果
经过多次对比测试,可知影响效率的主要因素为scan和sort函数以及输入txt的大小。结果与评审结果一致,无需对函数进行改进,效率已经很高了。
实践总结
经过了此次实验,我认为软件开发、软件测试、软件质量之间的关系是,软件开发是基础,即首先应该完成项目的需求,软件测试要穿插其中,用来发现软件不符合需求的地方,软件质量可以放在最后来实现但也要时刻注意,用来提高整个项目的质量。这三个也是密不可分的,三者结合起来才能是项目实现的最好。
小组贡献
根据全员的讨论结果,我的小组贡献分为0.25
参考文献
https://blog.csdn.net/u010180815/article/details/52208924
https://blog.csdn.net/jaune161/article/details/40025861
https://www.cnblogs.com/bhlsheji/p/4807669.html
https://www.cnblogs.com/EasonJim/p/7685724.html
https://zhidao.baidu.com/question/117274778.html
https://blog.csdn.net/u013132051/article/details/54345742
https://www.cnblogs.com/fnlingnzb-learner/p/6018604.html
https://zhidao.baidu.com/question/406042091.html
https://www.cnblogs.com/huangye-dream/archive/2013/03/01/2938937.html