此项目码云链接

软件测试方法和技术第二次作业

1 作业内容

根据WordCount的需求描述,先编程实现,再编写单元测试,最后撰写博客。至少完成需求中的基本功能。

2 WordCount需求说明

WordCount的需求可以概括为:对程序设计语言源文件统计字符数、单词数、行数,统计结果以指定格式输出到默认文件中,以及其他扩展功能,并能够快速地处理多个文件。

2.1 基础功能

wc.exe -c file.c //返回文件 file.c 的字符数

wc.exe -w file.c //返回文件 file.c 的单词总数

wc.exe -l file.c //返回文件 file.c 的总行数

wc.exe -o outputFile.txt //将结果输出到指定文件outputFile.txt

注意:

空格,水平制表符,换行符,均算字符。

由空格或逗号分割开的都视为单词,且不做单词的有效性校验,例如:thi#,that视为用逗号隔开的2个单词。

-c, -w, -l参数可以共用同一个输入文件,形如:wc.exe –w –c file.c 。

-o 必须与文件名同时使用,且输出文件必须紧跟在-o参数后面,不允许单独使用-o参数。

2.2 扩展功能

wc.exe -s //递归处理目录下符合条件的文件

wc.exe -a file.c //返回更复杂的数据(代码行 / 空行 / 注释行)

wc.exe -e stopList.txt // 停用词表,统计文件单词总数时,不统计该表中的单词

[file_name]: 文件或目录名,可以处理一般通配符。

其中,

代码行:本行包括多于一个字符的代码。

空 行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:

}//注释

在这种情况下,这一行属于注释行。

-e 必须与停用词文件名同时使用,且停用词文件必须紧跟在-e参数后面,不允许单独使用-e参数。

stopList.txt中停用词可以多于1个,单词之间以空格分割,不区分大小写,形如:

while if switch

则while,if,switch作为3个停用词,在单词统计的时候不予考虑。停用词表仅对单词统计产生影响,不影响字符和行数的统计。

2.3 高级功能

wc.exe -x //该参数单独使用,如果命令行有该参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、单词数、行数等全部统计信息。

3 解题过程

解题思路

本作业总体而言比较简单,因此采用面向过程方法就可轻松完成。首先我们知道,Main函数的args[]参数用于储存输入参数。那么命令中的**-o**,**-w**,**-c**等参数的检测就可以交给它来解决。这里为了方便,我们约定- w|c|l|a,-o的输入顺序。也就是说,先指明要操作的文件及命令再指明输出文件

step1 对输入进行检测

出于程序的健壮性考虑,首先要实现的功能应是输入检测。检测内容主要有以下几点
**参数名是否正确**
**参数是否重复输入**
**参数输入顺序是否正确**
**文件名是否符合规范**
**若符合规范,文件是否存在**

参数检测
```
for (i = 0; i < args.Length; i++)
{ //fchar等是初始值为0的int型标志符,每个参数对应一个
if (args[i] == "-c")
{ fChar++; }
else if (args[i] == "-w")
{ fWord++; }
else if (args[i] == "-o")
{ fOutput++; }
else if (args[i] == "-l")
{ fLine++; }
else if(args[i] == "-a")
{ fMore++; }
else if(args[i] == "-s")
{ fRecursion++; }
}
```

对于-o参数除了更改标识符外还要进行赋值操作,其中fileName和ResultFile均为全局变量

                if (args[i] == "-o")
{
if (fChar == 0 && fWord == 0 && fLine == 0)
{ //标识符为0说明在-o参数前面并没有- c|w|l|a 参数
Console.WriteLine("错误的命令,若使用-o参数请先在前面使用-c或-w或-i或-l指令");
return false;
}
fileName = args[i - 1]; //-o参数前一个参数必定为操作文件
ResultFile = args[i + 1]; //-o参数后一个参数必定为储存文件
}

参数重复检测

            if (fChar > 1 || fWord > 1 || fOutput > 1 || fLine > 1 || fMore > 1)
{ //如果大于一表示输入了至少两个重复参数
Console.WriteLine("输入的参数不能重复,请修改后再输入");
return false;
}

文件规范检测

            if (!Regex.IsMatch(fileName, "\\w*\\.(txt|c|docx)"))
{ //检查操作文件格式,利用正则表达式,存储文件的检测同理,将fileName更改为ResulFile即可
Console.WriteLine("Wrong filename,please try again!");
Console.WriteLine("Allowed filename:*.(txt|c|docx)");
return false;
}

文件是否存在

            if(!File.Exists(fileName))
{ //不存在该文件
if (!Regex.IsMatch(fileName, "\\*\\.(txt|c|docx)"))
{ //如果文件名格式不为*.c|txt|docx
Console.WriteLine("文件不存在!请重新输入");
return false;
}
}
  • 基础功能的实现

    对于-c,-w,-l,-a实现的基本思路相同。读取文件内容——>对内容进行处理——>保存需要记录的数据——>关闭文件流

    上述四个参数可分别作为四个方法,WordsCount(),CharCount(),LineCount(),MoreCount().其中对于文件的处理均采用StreamReader,保存到字符串Str中
StreamReader sr = new StreamReader(fileName);    //打开文件
string str = sr.ReadToEnd(); //读取并保存到str字符串中

四者字符串处理方法不同,字符计数可新建Char[]变量,再将读出的文件内容赋值,char数组的长度即为字符数.

char[] output = str.ToCharArray();

单词计数则利用字符串的split()方法,将读出的内容用','和‘ ’隔开再赋值给string[],string数组的长度即为单词数

string[] Words = str.Split(' ', ',');

行数与单词计数同理,也是利用Split()方法,只是分隔符变成了'\n',string数组的长度即为行数

string[] Lines = str.Split('\n');

代码行/注释行/空行,由于是对每行进行判断,先用string.Split('\n')将文件内容赋值给string数组More[],然后对每一行More[i]进行判断。具体代码如下

  for(i = 0;i < More.Length;i++)
{
chr = More[i].Replace(" ", "").Replace("\t","").ToCharArray(); //去掉空格和制表符
if(chr.Length > 1)
{ //字符数大于一,可能是代码行,可能是注释行
if(chr[0] == '}' || chr[0] == '{' && chr[1] == '/' && chr[2] == '/')
{ //去掉空格后如果包括{或}加上//则为注释行
aNote++;
}
else
{ //否则是代码行
aCode++;
}
}
else
{ //去掉空行后字符数小于一,则是空行
aEmpty++;
}
}

其中aNote、aCode、aEmpty为int型计数变量,其他参数也每个对应一个

- 参数-s的实现
首先获取当前目录及其子目录下所有的文件信息,然后找出符合文件名要求的文件进行对应处理,代码如下
        /// <summary>
/// 用于递归处理目录下符合条件的文件
/// </summary>
static void Recursion()
{
List<FileInfo> file = GetAllFilesInDirectory(".\\"); //此方法为自定义方法,返回值为FileInfo类型的列表
string[] suffix = fileName.Split('.'); //文件后缀
string pattern = fileName.Replace("*.", "\\w*\\.").Replace(suffix[1], "") + "(" + suffix[1] + ")$"; //将文件名在正则式正确表达出来
foreach(var f in file)
{
if (Regex.IsMatch(f.Name, pattern))
{ //如果文件名符合正则表达式
fileName = f.Name;
//根据参数决定该调用哪些方法
if (fChar > 0)
CharCount(); //字符计数
if (fWord > 0)
WordsCount(); //单词计数
if (fLine > 0)
LinesCount(); //行数计数
if (fMore > 0)
MoreCount(); //代码行、空行、注释行计数 Print(); //将结果输出到屏幕,print为自定义方法
}
}
}

由于题目要求无论参数顺序输出顺序相同,故将输出作为一个方法Print()

 static void Print()
{
if (fChar > 0)
Console.WriteLine(fileName + ",字符数:" + aChar.ToString());
if(fWord > 0)
Console.WriteLine(fileName + ",单词数:" + aWord.ToString());
if(fLine > 0)
Console.WriteLine(fileName + ",行数:" + aLine.ToString());
if (fMore > 0)
{
string print = string.Format("代码行/空行/注释行:{0}/{1}/{2}", aCode, aEmpty, aNote);
Console.WriteLine(print);
}

在主界面调用方法即可

  static void Main(string[] args)
{
//检查参数,此外-o参数在此方法已解决
if(!Check(args))
{
return;
} //根据参数决定该调用哪些方法
if (fRecursion > 0)
{
Recursion(); //循环
return;
}
if (fChar > 0)
CharCount(); //字符计数
if (fWord > 0)
WordsCount(); //单词计数
if (fLine > 0)
LinesCount(); //行数计数
if (fMore > 0)
MoreCount(); //代码行、空行、注释行计数 Print(); //将结果输出到屏幕
}

测试

测试文件



测试数据







总结

通过这次作业,我对于文件的操作掌握得更加好,并且对于软件测试也有了更深的了解

最新文章

  1. GSM07.10协议中串口复用使用的校验算法
  2. seo优化urlrewrite伪静态技术
  3. 使用 Sandcastle 生成代码帮助文档
  4. doctrine2到底是个什么玩意
  5. css自定义字体
  6. 【POJ 1035】Spell checker
  7. APM终端用户体验监控分析(下)
  8. EXTJS 3.0 资料 控件之 Toolbar 两行的用法
  9. ant -verbose -debug ...
  10. 统一建模语言(UML) 版本 2.0
  11. springmvc 双亲上下文导致的 No mapping found for HTTP request
  12. 【转】Android onTouch()和onTouchEvent()区别
  13. Android开源项目pulltorefresh分析与简单使用
  14. 设计模式之职责链模式(Chain of Responsibility)摘录
  15. ASP.NET\MVC 解决C#上传图片质量下降,图片模糊,水印有杂点的问题
  16. 201521123080《Java程序设计》第9周学习总结
  17. 实战DeviceIoControl 之六:访问物理端口
  18. Centos7安装搜狗输入法.
  19. Golang 入门系列(十一)Go语言实现webapi
  20. vue获取路由地址栏url里面的指定参数

热门文章

  1. Mybatis配置错误:java.lang.ExceptionInInitializerError
  2. 半吊子菜鸟学Web开发 -- PHP学习3-文件
  3. Adobe AIR 应用程序图标详细描述
  4. Mysql查询优化器之基本优化
  5. Switch语句的条件只能接受什么类型的值
  6. 名词解析-RPC
  7. 学习k8s(一)
  8. nginx静态资源服务器配置
  9. C# 将Excel转为PDF时设置内容适应页面宽度
  10. java中哪块代码或说什么代码应该放在try块中呢?