WordCountPro小结
GitHub地址
https://github.com/BluesJiang/WordCountPro
PSP表格
PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
·Planning | 计划 | 20 | 20 |
·Estimate | ·估计这个任务需要多少时间 | 20 | 30 |
·Development | ·开发 | 60 | 60 |
·Analysis | ·需求分析(包括学习新技术) | 30 | 40 |
·Design Spec | ·生成设计文档 | 20 | 20 |
·Design Review | · 设计复审 (和同事审核设计文档) | 20 | 10 |
·Coding Standard | ·代码规范 | 10 | 10 |
·Design | ·具体设计 | 30 | 30 |
·Coding | ·具体编码 | 120 | 135 |
·Code Review | ·代码复审 | 60 | 60 |
·Test | ·测试 | 150 | 150 |
·Reporting | ·报告 | 30 | 60 |
·Test Report | ·测试报告 | 30 | 30 |
·Size Measurement | ·计算工作量 | 10 | 5 |
·Postmortem&Process Improvement Plan | ·事后总结 并提出过程改进计划 | 30 | 30 |
·合计 | 640 | 650 |
基本任务
代码设计
我在此次小组作业中主要负责完成核心功能的编写,采用的是词法分析自动机的方法,设计的类主方法如下:
public HashMap<String, Integer> count(String filename)
该方法需要的参数是filename,是IOController类中的输入提供的文件,返回值是HashMap表,以此来提供给输出,,输出对Map排序之后写入文件。
下面是略过分隔符:
// skip char that isn't hyphen or isn't in English Alphabet
while (nowChar != -1 && !(isEngChar((char)nowChar)) && !(isHyphen((char)nowChar))) {
nowChar = reader.read();
}
下面是词法处理,有两种单词属于此次认为正确的单词,一种是纯英文的字符组合,一种是加了连词符号的字符组合:
// judge a legal word
while (nowChar != -1 && (isEngChar((char)nowChar) || isHyphen((char)nowChar))){
//specially dealing the Hyphen,divided into three conditions
if (isHyphen((char)nowChar)) {
nowChar = reader.read();
if (isEngChar((char)nowChar)) {
// first condition: Hyphen is in front of EngChar.
if ("".equals(nowWord)) {
nowWord += String.valueOf((char)nowChar) ;
} else {
// second condition: Hyphen is between with EngChars.
nowWord += "-" + String.valueOf((char)nowChar) ;
}
nowChar = reader.read();
} else {
// third condition: Hyphen is in the end of EngChar.
break;
}
}
if (isEngChar((char)nowChar)) {
nowWord += String.valueOf((char)nowChar);
nowChar = reader.read();
}
}
下面是将识别好的字符加入到HashMap(注意大小写问题)中:
// all convert to Lowercase words
nowWord = nowWord.toLowerCase();
if (wMap.containsKey(nowWord)) {
wMap.put(nowWord, wMap.get(nowWord) + 1);
} else if (!"".equals(nowWord)) {
wMap.put(nowWord, 1);
}
测试用例设计
因为单元测试要包括:InterfaceLocal 、data structure、Boundary、Independent path、Error handling,所以针对这个版块设计的测试用例应当参考这些。首先对于接口测试应该主要设计测试文件路径,包括相对路径和绝对路径问题进行的测试;针对数据结构和边界进行的测试要测试各种代表性的分隔符和大小写字符等等,错误控制主要测试面对文件参数传入不正确,识别单词不对等各种内部缺陷的记录.
单元测试应当有代表性,典型性,能发现错误,能记录测试过程,所以在设计过程中会注意到这些,详情见下。
单元测试--白盒测试
这针对连词符号作为分隔符的测试,分为两种情况,一种出现在词语前面,test检测所识别记录的单词和词频是否正确;一种出现在词语后面,test检测所识别记录的单词和词频是否正确:
hyphen-
-hyphen
@Test
@DisplayName("Bord test: wc.count(startWithHyphen.txt)")
void testCountFileStartWithHyphen() {
String fileName = "startWithHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
assertEquals(true, result.containsKey("hyphen"));
}
@Test
@DisplayName("Bord test: wc.count(startWithHyphen.txt)")
void testNumberStartWithHyphen() {
String fileName = "startWithHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
assertEquals(1, result.size());
}
@Test
@DisplayName("Border test: wc.count(endWithHyphen.txt)")
void testCountFileEndWithHyphen() {
String fileName = "endWithHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
assertEquals(1, result.size());
}
@Test
void testCountHyphen() {
String fileName = "endWithHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
HashMap expect = new HashMap(1);
expect.put("hyphen", 1);
assertEquals(expect.keySet(), result.keySet());
for (Object key: expect.keySet()) {
assertEquals((int)expect.get(key), (int)result.get(key));
}
}
当连词符号出现在字符之中的时候,出现两次,应当识别为两个不同的单词,作为分隔符来识别,此时test检测如下:
night--day
@Test
@DisplayName("Border test: single quotation mark")
void testCountFileWithContinuedHyphen() {
String fileName = "continuedHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
assertEquals(2, result.size());
}
@Test
@DisplayName("Border test: single quotation mark")
void testFileWithContinuedHyphen() {
String fileName = "continuedHyphen.txt";
String relativePath = fileParentPath + fileName;
WordCounter wc = new WordCounter();
HashMap result = wc.count(relativePath);
HashMap expect = new HashMap(1);
expect.put("night", 1);
expect.put("day", 1);
assertEquals(expect.keySet(), result.keySet());
for (Object key: expect.keySet()) {
assertEquals((int)expect.get(key), (int)result.get(key));
}
}
单元测试--黑盒测试
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10, 30]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10, 30]
},
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [100, 300]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [100, 300]
},
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [1000, 3000]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [1000, 3000]
},
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
{
"num_of_type": 11,
"word_size": [1, 37],
"sep_size": [1,5],
"word_repeat": [100, 200]
},
{
"num_of_type": 11,
"word_size": [1, 37],
"sep_size": [1,5],
"word_repeat": [100, 200]
},
{
"num_of_type": 11,
"word_size": [1, 57],
"sep_size": [1,5],
"word_repeat": [100, 200]
}
运行
由上图可以看出,每个单元测试都能正确通过,其中39ms的是因为hashmap的查找循环比较耗时,总体质量较好。
test case 0 generated
test case 1 generated
test case 2 generated
test case 3 generated
test case 4 generated
test case 5 generated
test case 6 generated
test case 7 generated
test case 8 generated
test case 9 generated
test case 10 generated
test case 11 generated
test case 12 generated
-------- setting test env --------
jar copyed to ./test
----------- testing --------------
number of test: 13
testing wcPro-0.0.1.jar
test 0 passed...time: 0.22666263580322266
test 1 passed...time: 0.2546083927154541
test 2 passed...time: 0.2154252529144287
test 3 passed...time: 0.3124823570251465
test 4 passed...time: 0.30092477798461914
test 5 passed...time: 0.5313186645507812
test 6 passed...time: 0.4945201873779297
test 7 passed...time: 1.5633094310760498
test 8 passed...time: 0.4977226257324219
test 9 passed...time: 1.5631704330444336
test 10 passed...time: 0.2659454345703125
test 11 passed...time: 0.28217220306396484
test 12 passed...time: 0.32783055305480957
test passed: 13 total: 13
扩展任务
采用了《阿里巴巴Java开发手册》中的规范,因为阿里巴巴企业规模较大,有着良好的开发风格和开发模式。
1【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行。
2. 【强制】if/for/while/switch/do 等保留字与括号之间都必须加空格。
3. 【强制】任何二目、三目运算符的左右两边都需要加一个空格。
4. 【强制】注释的双斜线与注释内容之间有且仅有一个空格。
正例: // 这是示例注释,请注意在双斜线之后有一个空格 String ygb = new String();
这些规定对于编码规范性有着很好地帮助,之前的符号还有大括号小括号等都是随心空格,很多时候换行不清晰,不明确,代码阅读极困难,这应用这些规定之后能够有效的解决这些困难。
静态检查
静态检查主要检查了17132的代码部分,采用的IntelliJ中的插件阿里巴巴code
guideline作为静态检查工具,下载地址请在IntelliJ中搜索相应内容,在分析之后指出该成员以下不足:
- 程序注释,程序在写好之后缺少很多必要的注释,单行注释应当在注释的上面展示。
- 部分判断顺序需要更改,改进之后可以提高程序效率和质量。
分析之后指出成员的一下优点:
程序思路清晰,变量命名符合规范。
程序各部分独立性好,便于更改。
静态扫描如下:
修改
根据静态测试的结果,做出了修改,修改结果部分展示如下,根据代码规范,发现出if,else后面应当追加大括号,虽然只可能有一句话,但是便于以后添加代码;在String类的比较我们可以发现“”空字符串与一个String变量比较相等时最好将空字符串放到外面:
高级功能
压力测试数据集
采用python脚本生成压力测试数据集,设计思路为:
- 测试单词大小写是一种情况,测试单词种类个数也是一种情况;
- 每个单词的重复次数以及分隔符个数也是压力测试的部分;
构建的测试集:
{
"num_of_type": 5,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
{
"num_of_type": 50,
"word_size": [1, 20],
"sep_size": [1,3],
"word_repeat": [10000, 30000]
},
测试集指标
所生成的压力测试文件大小分别为:1819kB与12427kB,并且成功通过了压力测试(单位s):
test 8 passed...time: 0.4977226257324219
test 9 passed...time: 1.5631704330444336
同行评审
主持人 | 评审员 | 记录人 | 作者 | 讲解员 |
---|---|---|---|---|
鲁平 | 鲁平、蒋志远 | 蒋志远 | 李露阳 | 李露阳 |
负责评审的流程 | 负责评审 | 负责记录 | 负责讲述设计思路 | 负责讲解 |
评审目的
检查出17132同学 在WordCountPro 代码核心功能以及单元测试中存在的缺陷
评审意见
评审员 | 评审意见 |
---|---|
鲁平 | 代码中有些部分没有合理的注释,应当添加适当详尽的说明 |
蒋志远 | 无明显缺陷 |
评审结论
没有发现实质性的 BUG,代码测试可以通过;但是该同学可以在代码规范上多多注意。
备注
由于工程量不是很大,每个人工作分开,所以这次代码部分没有很大的缺陷。
小组贡献率
| Contributor |
---|---|
蒋志远 | 37% |
李露阳 | 30% |
鲁平 | 33% |
作业小结
一款软件的开发很重要的就是要满足用户需求,产生出高质量高效率的软件产品,这次单元测试和静态测试之后我能够明显地感觉到之前的软件开发人工性占了很大的比重,简单地几组数据就认为这次程序完整无误是很不科学的;在这次反复测试反复改进中,我认为软件测试对于软件开发而言占了很大的比重,从需求分析到设计,再到编写,软件测试贯穿了整个开发过程,正因为有了软件测试的保证,才能够是的软件质量得到很大的提升和保证。