WordCount编写测试历程
WordCount
项目概述
WordCount的需求可以概括为:对程序设计语言源文件统计字符数、单词数、行数,统计结果以指定格式输出到默认文件中,以及其他扩展功能,并能够快速地处理多个文件。
该应用程序所在的完整JAVA环境和exe执行文件位于github(很抱歉20号的commit因为网络原因没有提交到上去,22号才发现,所以22号提交包含了20号的,两次一样的)请参阅[(https://github.com/YangLeee/WordCount )]
PSP表格
PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
·Planning | ·计划 | 20 | 20 |
·Estimate | ·估计这个任务需要多少时间 | 10 | 10 |
·Development | ·开发 | 300 | 420 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 60 |
· Design Spec | · 生成设计文档 | 30 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
· Design | · 具体设计 | 20 | 60 |
· Coding | · 具体编码 | 300 | 360 |
· Code Review | · 代码复审 | 60 | 90 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 30 | 120 |
· Test Report | · 测试报告 | 30 | 90 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 1000 | 1410 |
项目设计过程分析
设计思路
拿到一个项目首先要读懂需求,从开发环境到需求的输入输出,算法就是通过给定的输入得到良定义输出的过程;这个文件统计从算法上说不是很难实现,所需要做的工作也不繁琐,因为有以前做编译器词法分析的经历,所以实现起来思路很清晰。JAVA语言开发以前学过但是很多都忘了,但是面向对象语言的语法基本上差不多,所以基本上找资料重点关于文件的输入输出;动态数组类的方法;诸如Hash表之类的可以存储单词的集合类;最后要生成exe文件则参考文档 手把手教你如何把jar文件,打包成jar文件以及转换为exe可执行文件 [1]。
程序设计实现
采用Java语言开发,所以主方法类提供程序进入入口,并且应该尽量简洁,所需要的处理可以使用其他类的方法;还应该有一个(最好一个)类来处理参数和文件路径,因为文件路径本身也是参数,而且不止一个。所以设计两个成员属性,一个存储参数,另一个存储文件路径,(注意该文件路径成员属性仅仅是用来存储输入文件的路径,包括递归处理输入文件)。其中具有的函数分为获取属性或者键值的函数,还有处理参数和文件的函数。
此外应当还有一个针对各个“-”参数的处理类,相关函数应对各个参数可以分别处理,并能够把处理结果返回给成员属性便于获取。
下面是Args类的设计思路:
下面是WCount类的设计思路
代码说明
关键代码说明:
下面是对参数的处理,参数建立HashMap,采用键-值,相比于HashSet只存储值而言能够更快处理键值关系的同时还可以将一些参数和文件关联起来。相关思路见函数,其中参考了《Java编程手册》[2]中的方法。
public HashMap<String, String> aBox = new HashMap<>();//参数存储,采用Map能更快查找
public ArrayList<String> readFoldName = new ArrayList<String>();//路径存储,为了边长采用ArrayList
void addArgs(String[] args) {//参数的处理存储
for(int i=0;i<args.length;i++) {
if(args[i].charAt(0) == '-') {
char now_char = args[i].charAt(1);
if(now_char == 'c'||now_char == 'w'||now_char == 'l'||now_char == 'a') {//文件读取的参数处理
aBox.put(String.valueOf(now_char), "");
}
else if(now_char == 'o'||now_char == 'e') {//拓展功能参数处理
// if(args[i+1].charAt(0) == '-'||i+1 < args.length) 回去会亲自查看自定义异常类;
aBox.put(String.valueOf(now_char), args[i + 1]);
i++;
}
else if(now_char == 's'){//递归处理的参数处理
String type = ".";//多路径的每次路径存储
char t = ' ';
int temp =0;
for(int k=0;k<args[i + 1].length();k++)
{
t = args[i+1].charAt(k);
if(t == '.') {
temp = k;
}
}
type = args[i+1].substring(temp, args[i+1].length());
createFolder(type);//添加到表中
}
}
else
readFoldName.add(args[i]);//正常的输入文件参数
}
}
下面是对参数的-e和-w的参数的同时处理,先计算词数,如果是停用词那就把记词数减少。
public void readFileWord(String fileName)throws IOException{//读取文件词数
FileReader reader =null;
try {
File file = new File(fileName);
if(!file.exists()) {
file.createNewFile();
}
reader = new FileReader(file);
int len = reader.read();
while(len != -1) {
String word = "";
while(len != -1 && !isNormalChar(len)) {//跳过分隔符
len = reader.read();
}
while (len != -1 && isNormalChar(len)) {
word += String.valueOf((char)len);
len = reader.read();
}
wNumber++;
if (this.stopList != null && this.stopList.contains(word)) {//去掉停用词
wNumber--;
}
if (len == -1) break;
}
reader.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
下面提供了一种选择功能,可以选择留下哪几个参数对应的功能来完成文件输出;就是一些分支语句。
public void InputFile(String readName,String fileName,String fun[]) throws IOException{//提供一种保存文件的方式
File file = new File(fileName);
try {
if(!file.exists())
file.createNewFile();
FileWriter fw = new FileWriter(file);
BufferedWriter bfw =new BufferedWriter(fw);
for(int i=0;i<fun.length;i++) {
if(fun[i].equals("-c")) {
bfw.write(fileName);
bfw.write(",字符数:");
bfw.write(String.valueOf(cNumber));
bfw.newLine();
}
if(fun[i].equals("-w")) {
bfw.write(fileName);
bfw.write(",单词数:");
bfw.write(String.valueOf(wNumber));
bfw.newLine();
}
if(fun[i].equals("-l")) {
bfw.write(fileName);
bfw.write(",行数:");
bfw.write(String.valueOf(line));
bfw.newLine();
}
if(fun[i].equals("-a")) {
bfw.write(fileName);
bfw.write(",代码行/空行/注释行:");
bfw.write(String.valueOf(demoLine) +"/"+ String.valueOf(spaceLine) +"/"+ String.valueOf(quLine));
bfw.newLine();
}
}
bfw.close();
fw.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
测试设计过程
首先,采用白盒测试中的语句覆盖和判断覆盖原则,对于每一组参数设计测试用例,因为首先参数的个数和顺序对于整个程序来说是一个高风险的地方,所以采用了参数个数以及参数组合测试,设计了以下几组测试用例:
单参数测试:
1、-c -w -l "readFile"基本参数测试
2、-a"readFile"扩展参数测试
多参数测试:
3、-c -w -l "readFile" -o "outFile"基本参数测试
4、-c - w -l -e "stopListPath" -o "filePath"停用词表参数测试
5、-c -w -l -s *.c -o "filePath" 数测试
混顺序参数测试:
6、-c - w -l -e -o "filePath" "stopListPath" 停用词表参数测试
对于读取的文件的进行路径测试,通过各种边界类编写成测试用的.c或者.txt文件测试,来完成路径测试。
参考文献和资料
[1]http://blog.csdn.net/sunkun2013/article/details/13167099
[2]《java编程手册》机械工业出版社