第四周作业之wcPro核心模块

# 第四周作业之wcPro核心模块的实现

## 一、基本任务:代码编写+单元测试

### 小组github地址

https://github.com/SkateCloud/wcPro

### PSP表格

<div style="text-align: left" align="center">
<table>
<thead>
<tr class="header"><th align="center">PSP2.1</th><th align="center">PSP阶段</th><th align="center">预估耗时(分钟)</th><th align="center">实际耗时(分钟)</th></tr>
</thead>
<tbody>
<tr class="odd">
<td align="center"><strong>Planning</strong></td>
<td align="center">计划</td>
<td align="center">30</td>
<td align="center">60</td>
</tr>
<tr class="even">
<td align="center">Estimate</td>
<td align="center">估计任务需要多少时间</td>
<td align="center">30</td>
<td align="center">60</td>
</tr>
<tr class="odd">
<td align="center"><strong>Development</strong></td>
<td align="center">开发</td>
<td align="center">120</td>
<td align="center">180</td>
</tr>
<tr class="even">
<td align="center">Analysis</td>
<td align="center">需求分析</td>
<td align="center">20</td>
<td align="center">30</td>
</tr>
<tr class="odd">
<td align="center">Design Spec</td>
<td align="center">生成设计文档</td>
<td align="center">20</td>
<td align="center">30</td>
</tr>
<tr class="even">
<td align="center">Design Review</td>
<td align="center">设计复审</td>
<td align="center">20</td>
<td align="center">30</td>
</tr>
<tr class="odd">
<td align="center">Coding Standard</td>
<td align="center">代码规范</td>
<td align="center">30</td>
<td align="center">10</td>
</tr>
<tr class="even">
<td align="center">Design</td>
<td align="center">具体设计</td>
<td align="center">30</td>
<td align="center">50</td>
</tr>
<tr class="odd">
<td align="center">Coding</td>
<td align="center">具体编码</td>
<td align="center">30</td>
<td align="center">40</td>
</tr>
<tr class="even">
<td align="center">Code Review</td>
<td align="center">代码复审</td>
<td align="center">30</td>
<td align="center">40</td>
</tr>
<tr class="odd">
<td align="center">Test</td>
<td align="center">测试</td>
<td align="center">50</td>
<td align="center">10</td>
</tr>
<tr class="even">
<td align="center"><strong>Reporting</strong></td>
<td align="center">报告</td>
<td align="center">70</td>
<td align="center">240</td>
</tr>
<tr class="odd">
<td align="center">Test Report</td>
<td align="center">测试报告</td>
<td align="center">30</td>
<td align="center">100</td>
</tr>
<tr class="even">
<td align="center">Size Measurement</td>
<td align="center">计算工作量</td>
<td align="center">20</td>
<td align="center">60</td>
</tr>
<tr class="odd">
<td align="center">Postmortem</td>
<td align="center">总结</td>
<td align="center">20</td>
<td align="center">80</td>
</tr>
<tr class="even">
<td align="center">&nbsp;</td>
<td align="center">合计</td>
<td align="center">280</td>
<td align="center">480</td>
</tr>
</tbody>
</table>
</div>

### 接口设计

- 接口描述

本人负责的是核心模块,即对输入的文件读取后的结果进行单词排序并存入`List`结构中准备输出

- 设计思路

对从输入模块获取的数据存入`hashMap`中,再将`Map`结构转变成`List`结构进行单词排序,为输出模块准备接口

- 实现过程

先使用`Map<String, Integer>`结构对输入模块传来的数据进行存储.
```java
HashMap<String,Integer> words = new HashMap<>();
String str = readFile(args[0]);
{
int state = 0;
int beginIndex = -1;
for (int i = 0; i <= str.length(); ++i) {
char ch = i == str.length() ? ' ' : str.charAt(i);
boolean isWordChar = ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '-';
if (state == 0 && isWordChar && ch != '-') {
beginIndex = i;
state = 1;
} else if (state == 1 && !isWordChar) {
String word = str.substring(beginIndex, i).toLowerCase();
words.put(word, words.getOrDefault(word, 0) + 1);
state = 0;
}
}
}
```

由于外部存储机构使用的是`Map.Entry<String, Integer>`,不便于排序等操作,所以将map转化为List结构,进行排序

```java
List<Map.Entry<String, Integer>> list = new ArrayList<>();
list.addAll(words.entrySet());
list.sort((lhs, rhs) -> {
int cmp = -lhs.getValue().compareTo(rhs.getValue());
if (cmp != 0) return cmp;
else return lhs.getKey().compareTo(rhs.getKey());
});
```

### 测试设计

保证设计的测试用例应至少覆盖函数中所有的可执行语句,同时主要空数组、最差情况、词频排序、字母排序、两者混合等各种情况设计测试用例。

![附件2截图]()

### 单元测试

使用测试脚本进行单元测试,过程如下

![测试脚本运行截图](http://r.photo.store.qq.com/psb?/V10RioZu2yUxV6/n1er*KNZRifOkCNiXWZBFPjPZzYkWW89C36Q0e27Yfk!/r/dA4AAAAAAAAA)

单元测试效果良好,没有报错

### 小组贡献
我们小组齐心协力, 攻克难关,积极讨论,指出问题,我认为我的小组贡献分是0.4

## 二.扩展任务:静态测试

### 1. 代码规范

我选择了代码风格规范中:断行与空白的{}行、分行、命名、下划线、大小写;

代码设计规范中:函数、错误处理、new和delete、类型继承,模块化

我的编程习惯与以上附录中所述规范大致相同。而在其他如代码审查等重要规范上有待提高。

### 2. 同组分析

我分析了自己的代码,缩进、断行风格整洁,命名简单明了,逻辑清晰易读,但在代码设计规范上,模块化不足,不易于进行团队的coding工作,经常在git操作上发生冲突.

最后决定将团队代码进行整合重构,重构任务由我完成,故最终贴出组长的重构代码

```java
public class wordcount {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
new wordcount().start(args);
long t2 = System.currentTimeMillis();
long dt = t2 - t1;
System.out.println(("Elapsed " + dt + "ms"));
}

private void start(String[] args) {
HashMap<String,Integer> words = new HashMap<>();
String str = readFile(args[0]);
{
int state = 0;
int beginIndex = -1;
for (int i = 0; i <= str.length(); ++i) {
char ch = i == str.length() ? ' ' : str.charAt(i);
boolean isWordChar = ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '-';
if (state == 0 && isWordChar && ch != '-') {
beginIndex = i;
state = 1;
} else if (state == 1 && !isWordChar) {
String word = str.substring(beginIndex, i).toLowerCase();
words.put(word, words.getOrDefault(word, 0) + 1);
state = 0;
}
}
}

List<Map.Entry<String, Integer>> list = new ArrayList<>();
list.addAll(words.entrySet());
list.sort((lhs, rhs) -> {
int cmp = -lhs.getValue().compareTo(rhs.getValue());
if (cmp != 0) return cmp;
else return lhs.getKey().compareTo(rhs.getKey());
});

try (FileWriter fout = new FileWriter("result.txt")) {
int maxsz = Math.min(list.size(), 100);
for (int i = 0 ; i < maxsz; ++ i) {
Map.Entry<String, Integer> item = list.get(i);
fout.write(item.getKey());
fout.write(' ');
fout.write(item.getValue().toString());
if (i != maxsz - 1)
fout.write('\n');
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

private String readFile(String path) { // 读文件
try {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, "UTF-8");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

}
```

### 3. 静态代码检查工具

使用的是IDEA的插件Ant Build中的检错功能
Ant Build是一个Java自动化生成工具,其检错功能用来检查类或者jar文件,用来发现可能的问题。检测完成之后会生成一份详细的报告,借助这份报告可以找到潜在的bug.

检测范围

- 常见代码错误,序列化错误
- 可能导致错误的代码,如空指针引用
- 国际化相关问题:如错误的字符串转换
- 可能受到的恶意攻击,如访问权限修饰符的定义等
- 多线程的正确性:如多线程编程时常见的同步,线程调度问题。
- 运行时性能问题:如由变量定义,方法调用导致的代码低效问题

### 4. 扫描结果

![扫描结果](http://r.photo.store.qq.com/psb?/V10RioZu2yUxV6/rDxJRHigmYxocOiCk0dbyIFU79kW7pc7KV8Xg8yQeP8!/r/dN0AAAAAAAAA)

检测结果在右上角,可以看出仅有少量警告,根据IDEA红线标注可发现大多是声明方式不是按照目前使用的java标准,没有发生内存泄露等问题.

### 5. 小组代码问题说明

- 由于进行了整合重构,所以模块化程度降低,不易维护,但程序执行效率上升
- 异常处理的不够全面,应该覆盖大部分的一场情况,以便于检查与调试

## 三. 高级任务:性能测试和优化

设计,评审,优化

选择10kb,50kb,182kb大小的txt文件进行测试,程序处理时长如下:

      输入输出:1ms,1ms,2ms

      单词统计:20ms,150ms,540ms

      词频排序:6ms,8ms,10ms

  单词统计时间与文件大小呈线性相关,其他两个模块占比较小,故程序性能主要受到文件大小影响。组内共同对代码结构和细节进行详细审查并与其他组程序对比,整理得到如下观点:

    1.整合重构是正确的,不仅增加了代码的可读性和规范性,还大幅增加了程序的性能

    2.将大部分功能模块聚集在一个类方法中,虽然会导致代码耦合度增高,不易于团队维护和再开发,但是减少了模块间相互调用的开销和随之产生的内存开销

## 小结

通过基本任务、扩展任务、到高级任务的完成以及中间遇到的许多困难,体现出了软件测试对于软件开发的重要性。在开发过程中,使用静态测试工具实时地检测自己的代码,可以改正自己不良的编程习惯,更能防患于未然,减少出现bug的可能;对自己的模块进行单元测试,可以保障自己代码的正确性,更是对其他开发成员和整个任务的负责,使软件开发能够一步一个脚印地稳定开展;对性能的分析与测试,能使软件的质量进一步提高,同事能总结开发经验,使自己设计的模块更加高效。

posted @ 2018-04-08 22:06  skatecloud  阅读(80)  评论(0编辑  收藏  举报