WordCountOptimized

1 基本任务,代码编写与单元测试

1.1 项目的github地址

github地址:(https://github.com/SuperScholar-Z/WordCountOptimized)

1.2 PSP表格

PSP2.1 PSP阶段 预估耗时实际耗时(分钟) 实际耗时(分钟)
Planning 计划 15 13
- Estimate 估计这个任务需要多少时 15 13
Development 开发 560 610
- Analysis - 需求分析(包括学习新技术) 120 130
- Design Spec - 生成设计文档 90 90
- Design Review - 设计复审(和同事审核 设计文档) 10 10
- Coding Standard - 代码规范 (为目前的开发制定合适的规范) 5 5
- Design - 具体设计 15 20
- Coding - 具体编码 200 210
- Code Review - 代码复审 40 35
- Test - 测试(自我测试,修改代码,提交修改) 80 110
Reporting 报告 60 80
- Test Report - 测试报告 30 40
- Size Measurement - 计算工作量 10 10
- Postmortem & Process Improvement Plan - 事后总结, 并提出过程改进计划 20 30
合计 635 703

1.3 个人接口及其实现

WordCount优化项目的模块划分为:
1.输入输出模块
2.单词分割模块
3.单词排序与单词类设计模块
4.单词计数模块
其中我负责的接口与模块是单词排序与单词类模块,具体实现的功能为对于单词根据词频由高到低进行排序,取频率最高的前100个单词,对于单词词频相同的单词,按照单词所包含的每个字母从a到z的次序依次排列。然后单词类的设计思路是该类中保存单词的字符串与单词出现的词频,需要时可以返回这两个属性值,并要对equals方法进行重写。
对于单词排序的外部接口,接受一个word类型的动态数组

public static void sort(ArrayList<Word> wordArr)  //对单词按出现次数降序排序

然后需要对Collection.sort()的方法进行重写,返回比较结果

Collections.sort(wordArr, new Comparator<Word>()
        {
            @Override
            public int compare(Word word1, Word word2)
            {
                if(word1.getNum() < word2.getNum())
                    return 1;
                else if(word1.getNum() == word2.getNum())
                    return word1.getStrWord().compareTo(word2.getStrWord());
                else
                    return -1;
            }
        }); //排序

对于单词类Word,该类的主要接口是返回或者修改单词的各种信息,比如说

 public String getStrWord()  //获取单词字符串
public int getNum() //获取单词出现次数
public void incNum()    //单词数量+1

1.4 测试用例的设计以及测试效率的满足

测试用例的设计主要根据课程中所学习到测试用例设计方法进行设计,总体可以分为白盒测试与黑盒测试。,
白盒测试中的逻辑覆盖方法大致可以分为以下几种:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖。是在了解程序逻辑结构的基础上对路径进行穷举测试,所以目标是对于单词排序的不同逻辑路径分支进行测试。
而黑盒测试则是在不考虑程序的内部结构的情况下对于程序进行功能测试,我的测试主要采用了边界值测试与等价类划分的方法
以下是部分测试用例的设计考虑

其中测试用例采用Junit的测试框架,单词排序测试方法类WordCountTest,测试运行类TestRunner
一共设计了22个测试用例,分别对应于WordCountTest中的Test后的二十种方法。
其中测试用例设计图如下:

代码举例分析

  @Test
    public void testResu() throws IOException                                   //对单词排序进行等价类测试,测试单词相同,词频相同,但顺序不同的测试结果是否相等
    {
        ArrayList<Word> wordArr = Process("test-8.txt");
        ArrayList<Word> wordArr2 = Process("test-9.txt");
        boolean result = false;
        if(wordArr.equals(wordArr2))
            result = true;
        assertTrue(result);
    }

该测试属于黑盒测试中的等价类测试,其中test-8.txt和text-9.txt属于内容相同,但是单词顺序不同的情况。
由于不同测试的划分比较合理,冗余度较小,故测试效率较高。

测试用例运行截图

单个用例的测试截图

1.5单元测试的运行截图


所有的测试用例均通过,故测试质量与被测模块质量均比较高

1.6讨论得出的小组贡献分

经过小组的讨论情况得出我的小组贡献率为:0.26

2 扩展任务:静态测试

2.1 编码规范

我选取的邹欣老师现代软件工程讲义3中的代码规范部分,并且详细阅读了其中的缩进,行宽,括号,断行与空白的{ }行,分行,下划线,注释,大小写和错误处理等部分。
其中我认为必须要遵守的部分如下:

1、缩进
用4个空格,在VS2005和其他的一些编辑工具中都可以定义Tab键扩展成为几个空格键。不用 Tab键的理由是Tab键在不同的情况下会显示不同的长度。4个空格的距离从可读性来说正好。

2、括号
在复杂的条件表达式中,用括号清楚地表示逻辑优先级。

3、断行与空白的{ }行
每个“{”和“}”都独占一行,如:

if ( condition)
{
    DoSomething();
}
else
{
    DoSomethingElse();
}

4、命名
命名的目的是让程序员一眼就能看出变量的类型,避免在使用中出错

(http://www.cnblogs.com/xinz/archive/2011/11/20/2255971.html)

2.2 代码分析

我分析的是我们组组长钟芳郅同学的代码,学号后五位17105,在此次的项目中他主要负责输入输出控制的部分,我选取了其中代码进行规范分析,首先,在代码的注释部分,钟芳郅同学采用了中文的注释,不符合代码规范中的注释只能采用ASCII字符的规范要求,容易引起软件的移植性问题。他在注释的详细程度上做的比较好,注释清楚明了。

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");

        System.out.println(wordArr.size());
        output.flush(); //把缓存区内容写入磁盘文件中
        output.close(); //关闭文件
    }

其次是程序的错误处理部分,在这个方面他做的比较好,仔细地考虑了程序的各种运行结果,并做出错误提示。

 if(errorType == 0)  //命令行输入格式错
            System.out.println("输入格式有误!");
        else if(errorType == 1) //窗口界面未打开文件
            System.out.println("未打开输入文件。");

然后是程序的变量命名部分,可以看出程序中函数名采用驼峰命名法,符合命名规范。而且变量的命名具有意义,可以看出来大体的功能,比如说outputFile

private static String getFilePathInDialog() //通过窗口界面打开文件

2.3 静态代码检查工具

由于我采用的编译器是intellj idea,所以我采用的代码检查工具为FindBugs,下载地址
(http://plugins.jetbrains.com/files/3847/29582/FindBugs-IDEA-1.0.1.zip?updateId=29582&pluginId=3847&uuid=d795e0ae-00bd-4334-82c3-95d6d34bb64e&code=IU&build=162.2032.8)
下图是代码检查工具的检查结果:

从代码的检查结果我们可以看得出来简单地重写equals的话会出现问题,这是因为在 equal 之前,首先会比较 Hash code。
如果连 Hash code 都不相等,那样就没有必要去调用 equal 了。
改进方法如下:
一般来说,如果你要把一个类的对象放入容器中,那么通常要为其重写equals()方法,让他们比较地址值而不是内容值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。然后需要对于hashCode()方法与compareTo()方法进行重写。

2.4 代码分析改进

代码分析改进后的运行

明显可以看出,代码经过改进后利用代码检查工具的检查结果比较好,并没有发现bug。

2.5 小组代码分析

经过整个小组对于代码的评价,代码存在的主要问题如下:
1.代码的规范程度不够,导致代码的可读性不强。
2.程序的可维护性不高。

3 高级任务:性能测试与优化

3.1 测试数据集的设计思路

首先,为了确定程序运行性能的基础情况,首先利用82行的test-2.txt的源文件进行第一步的测试情况,为了获取程序的性能数据,首先,我们可以获得程序运行前的系统时间,然后在程序运行后再次获取当前系统的时间,然后两者相减可得程序的具体运行时间。代码如下

long startTime = System.currentTimeMillis();    //获取开始时间
long endTime = System.currentTimeMillis();    //获取结束时间
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

3.2 运行时间

test2.txt的测试运行结果如下:
程序运行时间:15ms
明显可以看出,这种数据量的文件对于程序带来的压力很小,所以对于程序的测试决定采用数据量比较大的文本,乔布斯传的英文原版《steve Jobs》,数据量如下:

该测试文本不仅能保证程序的测试的数据量的大小,而且由于测试来自于英文名著,可以避免特殊情况对于程序的影响。
运行结果如下图所示:

运行四次的平均结果是5837ms。

3.3 同行评审

同行评审参加的参加人员为小组的四个成员
主持人:钟芳郅17105

作者:钟芳郅17105、刘弋17108、胡天池17124、黄一桐16316

讲解员:钟芳郅17105、刘弋17108、胡天池17124、黄一桐16316

评审员:刘弋17108、胡天池17124

记录员:黄一桐16316

其中评审意见与评审结论如下:
1、程序效率主要受核心功能即单词分割、统计计数、排序影响。
2、统计计数,由于要在数组中查找该单词是重复出现的单词还是新出现的单词,因此此时使用Map容器会比ArrayList容器更为快捷,因此Map容器基于二叉树,按值查找的效率较快。
3、排序时使用较高效的算法,如归并排序,可以加快排序的效率。

3.4 实际测试的结论

通过实际的测试,我们发现实际测试的结果中影响程序效率的因素主要是排序方法与核心功能实现的影响,与同行评审的意见相一致。

3.5 优化的设计思路

1、排序时使用较高效的算法,如归并排序,可以加快排序的效率。
2、统计计数,由于要在数组中查找该单词是重复出现的单词还是新出现的单词,因此此时使用Map容器会比ArrayList容器更为快捷,因此Map容器基于二叉树,按值查找的效率较快。
3、一定要注意文件的读写操作,因为文件的读写操作相对于内存操作来说,速度非常慢,因此编程时一定要严格控制文件读写的词数,并且文件的输入输出流在使用完成之后一定要注意关闭。

3.6 优化后的运行结果

将ArrayList改为Map的后运行结果如下图所示:

程序运行时间将会由5000ms-6000ms变成200ms-300ms,程序的优化效率十分显著,是因为Map容器的查找效率非常高。

3.7 软件开发、软件测试、软件质量之间的关系

在本次实验中,基本任务主要体现了软件的开发阶段,但是也在此阶段也要保证开发软件的质量,而扩展任务主要体现了软件的测试过程,高级功能主要是为了提高软件的质量。在这次的项目合作中,我发现在实际的软件开发过程中,实际上软件开发,软件测试与软件质量是不能轻易分开的,比如说在软件的开发过程中如果不注重编码规范,代码的质量难以保证,即使后面想要提高软件的质量也并不容易,因为代码的风格大体是在软件开发过程中确定的,而且软件的测试也要伴随着软件的开发过程,软件的质量必须要在软件开发的全阶段中加以注重,这样才能保证我们能开发出符合质量要求的软件产品。

posted @ 2018-04-08 19:46  刘弋  阅读(227)  评论(2编辑  收藏  举报