基础任务
一、https://github.com/SuperScholar-Z/WordCountOptimized
二、PSP表格
三、单词计数模块的主要代码如下:
public void Count() throws IOException //统计单词数
{
String line; //读取的一行文本
while ((line = input.readLine()) != null)
{
//单词分割
ArrayList<String> wordST = new ArrayList<>();
WordSplit.split(line, wordST); //单词分割
if(wordST == null)
continue;
for(String m_strWord : wordST) //提取出分割的单词
{
Word m_word = new Word(m_strWord); //逐个单词读入
int indexOfWord = wordArr.indexOf(m_word); //单词在容器中的位置
if (m_word.getStrWord().length() == 0) //跳过空字符串
continue;
if (indexOfWord == -1) //单词第一次出现则放进容器
wordArr.add(m_word);
else //单词重复出现则计数器+1
wordArr.get(indexOfWord).incNum();
}
在这次小组的作业中,我负责的是单词计数的模块,实现起来并不难。
首先会读取目标文件,然后调用单词分割模块,将分割好的单词放在数组里。
然后就进行计数了,如果是一个新的单词,那么就将它加入容器,如果是已经计数过的单词,就将那个单词的数量加一。
四、单元测试设计
本次测试主要采用白盒测试,并参考黑盒测试方法。其中,白盒测试主要为语句覆盖和条件覆盖。
首先,这个模块并不难,主要的代码也不多,即使是语句覆盖,也不够二十个,因此,在考虑测试用例时会理所当然的想到排列组合。
由于各组员所负责模块不同,测试时只测试本模块正确性,所以本次测试默认单词分割和输入输出模块正确,并在测试中去除了排序模块。
所以,本模块从条件上划分:1、是否为空文件
2、分割过后所读到的字符串是否为空字符串
3、是否已经读到过(string已在容器中)
因此按照条件和语句的划分,本次采用了20个用例。
五、单元测试结果
运行截图如下:
对于此次测试来说,结果较为理想。
此模块的内容不多,但是用例却有很多,因此测试的覆盖范围较广,但是却显得20个用例有些冗余了。
扩展任务
一、参考规范“现代软件工程讲义 3 代码规范与代码复审”
http://www.cnblogs.com/xinz/archive/2011/11/20/2255971.html
个人理解:代码规范分为代码风格规范和代码设计规范。
代码风格规范:文字上的规定,我认为这个的最重要的目的是为了方便阅读,方便他人方便自己,方便代码重写重用。
平时我自己做的比较好的有:缩进、行宽、括号、断行、分行等。
而平时所做的不够好的地方就是命名和注释:
命名:我自己一般是命名比较随意的ijk或者什么单词的甚至为拼音的命名,而这么做是不对的。
现在比较常见为匈牙利命名法,在变量前加上前缀,可以一眼看出变量的类型和相应的语义。
注释:我的注释要不然是忘了写,要不就是想起来然后写很多。
但是,实际上应该将注释精简,并且将其中复杂的注释放在函数头。
代码设计规范:宏观上各部分的通用原则。我认为这里很重要的我平时用的到但我处理的不够好的是异常处理。
异常处理:我认为这个异常处理并不是像输入输出的时候一个简单的try和catch,而是代码的方方面面。
比如说各种边界值之类,在对容器文件等操作前判断是否为空,各类值是否会溢出越界等等等等。
二、小组组员部分代码分析
17105同学的部分代码(输出文件函数)
private static void ResultOutput(ArrayList<Word> wordArr) throws IOException //输出统计结果
{
File outputFile = new File("result.txt"); //打开存储文件
BufferedWriter output = new BufferedWriter(new FileWriter(outputFile)); //输出缓冲区
for(Word word : wordArr) //将统计结果写入缓冲区
output.write(word.getStrWord() + "\t" + word.getNum() + "\r\n");
output.flush(); //把缓存区内容写入磁盘文件中
output.close(); //关闭文件
}
我认为他的代码就是我们所有人的楷模,从风格到设计,都很符合规范:比如说缩进、空行、注释以及异常处理,还有文件的关闭收尾工作。
三、使用findbugs工具。
下载地址:http://findbugs.sourceforge.net/
四、对本次代码进行扫描,结果如下图:
没有出现bug
但是有着编程方面的坏习惯,命名问题:Count函数开头应为小写字母;字符串比较应用.equal()方法
还有一个问题是对于输出格式的问题,没有指定格式。
解决方法:加一句FileOutputStream(outputFile),"UTF-8")));
以指定文件的输出编码格式为"utf-8"。
五、小组讨论
整个小组存在问题基本相同,没什么大问题,命名上有点小问题,注释非英文,其他的都还好,因为扩展任务的都是调试过的,没有设计问题。
高级任务
一、测试集选用了乔布斯传,具体参数信息如下:
二、优化前性能指标
测试了十次结果分别为:
程序运行时间:2315ms
程序运行时间:2276ms
程序运行时间:2277ms
程序运行时间:2191ms
程序运行时间:2200ms
程序运行时间:2287ms
程序运行时间:2389ms
程序运行时间:2338ms
程序运行时间:2294ms
程序运行时间:2336ms
平均运行时间:2290.3ms
三、同行评审
本次评审所担任角色为:
作者:钟芳郅、胡天池、黄一桐、刘弋。
讲解员:钟芳郅、胡天池、黄一桐、刘弋。
评审员:胡天池、刘弋。
主持人:钟芳郅。
记录员:黄一桐。
评审过程:由主持人主持,各小组成员讲解自己所负责的模块的代码,评审员提出评审意见,记录员负责记录,最终讨论得出评审结论。
评审意见和结论:本程序效率主要受核心功能即单词分割、统计计数、排序影响。
四、性能分析
通过测试,我们发现制约程序性能指标的主要因素是单词分割、计数、排序方面,即和同行评审结果相似。
五、性能优化
1、统计计数,由于要在数组中查找该单词是重复出现的单词还是新出现的单词,因此此时使用Map容器会比ArrayList容器更为快捷,因此Map容器基于二叉树,按值查找的效率较快。
2、排序时使用较高效的算法,如归并排序,可以加快排序的效率。
优化后的性能指标如下图:
此次优化十分理想,将类的ArrayList换成hashmap之后,程序的运行时间降低到了0.135左右。十次运行结果在0.126~0.142之间。
六、总结
软件开发、软件测试、软件质量这三者是密不可分的。其中,软件开发属于前期工作,软件测试为后期工作,但是,在软件的开发过程中也会进行许许多多的测试,去保证程序的正确性,找出程序的错误,但是这个阶段测试的方法可能不太规范。而在软件测试阶段,我们需要以更缜密的思维,并使用规范科学的方法去设计测试用例,并使之保证无误。而在之后的静态测试,结果还算理想。我是第一次知道并且使用工具对代码进行测试,知道了还可以使用工具找出程序中的问题及规范性,再今后还是可以借鉴的。最后的性能测试则是另一重点,这与软件质量是息息相关的,一个好的程序离不开优化,对程序的优化可以使性能大大提升。
七、小组贡献率
0.23