github:https://github.com/skz12345/WordCount

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

代码部分参考了MasonWater在https://github.com/MasonWater/WCProject所提交的代码,本次测试基于本程序进行测试。

解题思路

根据作业要求,可以分析出此次作业有多个输入参数,根据参数的不同,实现一些有严格要求的功能。关于多参数的传递,选择使用main函数传参的方法。通过查阅资料【1】,找到了java如何读取文件内容,通过此方法,按照作业要求对各项数据进行统计,用代码得以实现。

程序设计实现过程(以下主要基于http://www.cnblogs.com/hayitutu/p/8613653.html,Wonderkid的博客)

程序包括一个类(wordcount),9个函数,其中包括一个main函数。其余8个函数为:

Operator函数(实现功能)、BaseCount函数(基本功能)、Display函数(设置输出到文件的字符串)、MoreCount函数(扩展功能)、getStopLisy函数(获取停词表中停词)、outputTxt函数(设置输出文件)、Bianli(实现递归处理)、getAllFile函数(获得符合要求后缀的文件名)。

main函数获取到参数后分类,将功能参数和文件参数分别存储之后用于生成wordcount类的一个对象。之后调用对象的Operator功能,循环遍历功能数组判断需要执行那些操作。根据参数判断来调用对应的函数。如事先判断是否有启用停词表的参数,若有则先调用getStopList函数获取停用词表,之后若参数是基本功能的参数,就调用BaseCount函数来统计,同时判断是否去除停词。若是扩展功能参数,如复杂行的统计则调用MoreCount函数来统计代码行,空行和注释行。若是递归调用功能参数则调用BianLi函数,BianLi函数调用getAllfile函数获取符合要求的文件队列然后递归执行相应的操作(BaseCount、MoreCount等)。在递归操作或者Operator执行过程中若有输出文件指定则将输出flag调整。最后调用Display函数设置输出到文件中的内容,之后调用outputTxt函数来根据输出flag输出到文件中。当完成基本功能后,将源文件上传到github仓库中,commit一次,之后完成程序再次上传,打包好exe后完成最后的上传。后续还上传了测试脚本和测试相关文件。

代码说明(以下主要基于http://www.cnblogs.com/hayitutu/p/8613653.html,Wonderkid的博客)

代码说明

BaseCount方法中去除停词时将文件按行读入【2】,通过逗号和空格分割单词后和停用词数组中词比较,统计去除词的个数,每行处理一遍。同时注意行开头空格的去除【3】

代码如下:

  1. BufferedReader st2 = new BufferedReader(new FileReader(this.sFilename));//统计单词数
  2. String read1 = null;
  3. int lengthofSplit=0;
  4. while (( read1 =st2.readLine()) != null)
  5. {
  6. read1=read1.trim();//去除空格
  7. String[] arrSplit =read1.split(" |,");//以空格或者逗号分隔
  8. lengthofSplit=arrSplit.length;
  9. for(String s:arrSplit)
  10. {
  11. if(s.length()==0)
  12. lengthofSplit--;//去除空格
  13. }
  14. wordcount+=lengthofSplit;
  15. if(openStopList==1)
  16. {
  17. for(String s:arrSplit)
  18. {
  19. for(String stop:StopList)
  20. if(s.equals(stop))
  21. stopWordCount++;
  22. }
  23. }
  24. }
  25. st2.close();

MoreCount方法中同样也是对文件按行读取,判断多行注释的时候和单行注释一样要判断注释前是否多于一个字符,这通过一个计数变量来实现,以及“/”后有字符则不算注释行,这也通过计数变量来实现。同时当有“/”开始后,设置多行注释的flag变量,当遇到“/*”时重置flag

代码如下:

  1. flagOfword=0;
  2. countOfword=0;
  3. numberOfMLines=0;
  4. BufferedReader brm = new BufferedReader(new FileReader(this.sFilename));
  5. String linem;
  6. int flagOfM=0;//标记是否有/*开始了
  7. int countss=0;//记录每行字符数以便判断是否是注释行
  8. int counts=0;//记录每行字符数以便判断是否是注释行
  9. while ((linem = brm.readLine()) != null)//判断/**/类型的注释行
  10. {
  11. String [] sss=new String[10000];
  12. if(flagOfM==1)
  13. numberOfMLines++;
  14. for (int x = 0; x < linem.length(); x++)
  15. {
  16. sss[x]=String.valueOf(linem.charAt(x));
  17. int temp=(x+1)<(linem.length()-1)? x+1:(linem.length()-1);
  18. if(flagOfM==0)
  19. { countss=0;//
  20. if(x<linem.length()-1&&sss[x].equals("/")&&linem.charAt(temp)=='*')
  21. {
  22. for(int i=0;i<x;i++)
  23. {if(linem.charAt(i)!=' ')
  24. { if(linem.charAt(i)=='\t')
  25. continue;
  26. countss++;
  27. }
  28. }
  29. if(countss>1)
  30. {
  31. flagOfM=0;
  32. }
  33. else
  34. {
  35. flagOfM=1;
  36. }
  37. continue;
  38. }
  39. }
  40. if(flagOfM==1)
  41. {counts=0;
  42. if(x<linem.length()-1&&sss[x].equals("*")&&linem.charAt(temp)=='/')
  43. {
  44. for(int i=temp+1;i<linem.length()-1;i++)
  45. {if(linem.charAt(i)!=' ')
  46. { if(linem.charAt(i)=='\t')
  47. continue;
  48. counts++;
  49. }
  50. }
  51. if(counts<=1)
  52. {
  53. numberOfMLines++;
  54. flagOfM=0;
  55. }
  56. else
  57. {
  58. flagOfM=0;
  59. }
  60. }
  61. }
  62. }
  63. }
  64. brm.close();

对于扩展功能里的递归读取符合要求的文件,这通过两个函数实现,BianLi函数调用getAllFile函数来筛选符合要求的文件之后的操作便是循环执行Operator函数的操作,所以BianLi函数不再赘述。关于getAllFile函数,函数有四个参数:文件路径、符合要求的文件/文件夹的存储数组、要筛选的类型以及筛选出来的文件数组。函数通过判断是否是文件夹来操作,若是文件夹则递归调用函数,否则判断类型后删选文件。

代码如下:

  1. private static List<String> getAllFile(File filePath,List<String> filePaths,String type,List<String> finalFiles){
  2. File[] files = filePath.listFiles();//递归获取文件夹以及子目录下的所有符合条件的文件
  3. if(files == null){
  4. return filePaths;
  5. }
  6. for(File f:files){
  7. if(f.isDirectory()){
  8. filePaths.add(f.getPath());
  9. getAllFile(f,filePaths,type,finalFiles);
  10. }else{
  11. if(f.getName().endsWith(type))
  12. {filePaths.add(f.getPath());
  13. finalFiles.add(f.getPath());}
  14. }
  15. }
  16. /*for(String path:finalFiles){
  17. System.out.println(path);
  18. }*/
  19. return finalFiles;
  20. }

测试设计过程

在线学习2.3节中对测试的判定中提到“要保证测试用例覆盖函数中的所有可执行路径”,以此为出发点,我尽可能精简的设计了10条测试用例。

一、基于基本功能的测试

基本功能是该程序的第一次提交所实现的内容,由以下4条测试用例测试基本功能:

  1. wc.exe -c -w file1.c
  2. wc.exe -l file.c -o output.txt
  3. wc.exe -l -c -w file1.c
  4. wc.exe -c -l -w file1.c

设计思想

基本功能的实现中,所有指令均为通过flag置位判断是否执行,flag的值只为0或1,在1,2两个测试用例中,交叉试验了-c -w -l -o四个功能,flag为0和为1全部覆盖。

在3,4两个测试用例中,测试了需求中要求的顺序是否能正确执行。

二、基于扩展功能的测试

扩展功能是该程序的第二次提交所实现的内容,有以下三条测试用例测试扩展功能:

  1. wc.exe -a file1.c
  2. wc.exe -s -a *.c
  3. wc.exe -w file1.c -e stoplist.txt

设计思想

测试用例5测试了返回更复杂的数据,测试用例6测试了递归处理,测试用例7测试了启用停用词表下统计单词总数功能是否正确。

三、综合测试

最后提交将两种功能叠加,进行总体测试,以下为三条测试用例:

  1. wc.exe -c -w -a -l file1.c
  2. wc.exe -w -a -c -l file1.c
  3. wc.exe -s -c -w -l -a *.c -o output.txt -e stoplist.txt

设计思想

测试用例8和9对于总顺序是否能正确执行进行测试,测试用例10对于系统最复杂的功能集合进行了测试。

在对错误输入的处理上,如果处理不当,往往会造成许多无法估计的后果,风险很高。

由于10条测试用例太少,并不能完全说明问题,预想中还应改变不同的代码,进行一些错误处理、临界值等的测试,将会在未来进行尝试。

参考文献

【1】https://blog.csdn.net/sky786905664/article/details/65626886

【2】https://www.cnblogs.com/xyzq/p/7095011.html

【3】http://blog.csdn.net/zhangzehai2234/article/details/73522041

WordCount-软件测试初体验的更多相关文章

  1. 全分布式的Hadoop初体验

    背景 之前的时间里对 Hadoop 的使用都是基于学长所搭建起的实验环境的,没有完整的自己部署和维护过,最近抽时间初体验了在集群环境下装机.配置.运行的全过程,梳理总结到本文中. 配置 内存:8G C ...

  2. Apache Beam入门及Java SDK开发初体验

    1 什么是Apache Beam Apache Beam是一个开源的统一的大数据编程模型,它本身并不提供执行引擎,而是支持各种平台如GCP Dataflow.Spark.Flink等.通过Apache ...

  3. .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验

    不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...

  4. Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验

    Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...

  5. Spring之初体验

                                     Spring之初体验 Spring是一个轻量级的Java Web开发框架,以IoC(Inverse of Control 控制反转)和 ...

  6. Xamarin.iOS开发初体验

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0

  7. 【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d13a57132ff21c38110186 导语 最近这几年的前端圈子,由于 ...

  8. 【Knockout.js 学习体验之旅】(1)ko初体验

    前言 什么,你现在还在看knockout.js?这货都已经落后主流一千年了!赶紧去学Angular.React啊,再不赶紧的话,他们也要变out了哦.身旁的90后小伙伴,嘴里还塞着山东的狗不理大蒜包, ...

  9. 在同一个硬盘上安装多个 Linux 发行版及 Fedora 21 、Fedora 22 初体验

    在同一个硬盘上安装多个 Linux 发行版 以前对多个 Linux 发行版的折腾主要是在虚拟机上完成.我的桌面电脑性能比较强大,玩玩虚拟机没啥问题,但是笔记本电脑就不行了.要在我的笔记本电脑上折腾多个 ...

  10. 百度EChart3初体验

    由于项目需要在首页搞一个订单数量的走势图,经过多方查找,体验,感觉ECharts不错,封装的很细,我们只需要看自己需要那种类型的图表,搞定好自己的json数据就OK.至于说如何体现出来,官网的教程很详 ...

随机推荐

  1. Codeforces 808F. Card Game

    题目大意 一个物品有三个属性 : 价值,键值,等级. 你不能选取等级高于\(level\)的物品,键值之和为质数的两个数字不共存. 问最低的等级使得可以选出价值之和超过\(k\)的物品. \(n\le ...

  2. 对django rest_framework的个人理解

    首先要搞清楚web service 和rest都是一种API设计的架构,简单点说 作为一个api开发者,为了保证跨语言.跨平台的高效api,我们可以采用架构师提出的设计架构的理念去设计符合条件的api ...

  3. ugui在运行时改变RectTransform的大小

    http://blog.csdn.net/BeiFuDeNvWang/article/details/50838266 在代码中动态改变RectTransform大小的方法如下所示: 1:直接对siz ...

  4. bzoj 3527 [Zjoi2014]力——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3527 把 q[ i ] 除掉.设 g[ i ] = i^2 ,有一半的式子就变成卷积了:另一 ...

  5. Ubuntu 16.04 LTS制作本地源

    平时apt-get install安装软件时,下载的deb文件都会存放在/var/cache/apt/archives/下,没有网络时就需要将这些deb制作成本地源.另外,如果在本机架一个简单的网络服 ...

  6. MySQL的varchar类型注意事项

    前几天就在工作中发现这样一个问题:当某个字段的类型为varchar时,字段保存的值类似'100,200,300'  和 '100' 或 '100,400'.写SQL语句的时候就会犯这样的错误,例如: ...

  7. hihoCoder#1067(离线算法求LCA)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中 ...

  8. Update多个字段从一个表中

    UPDATE XXXXXX S SET (S.XXX, S.CCC, S.DDD, S.AAA, S.BBB) = (SELECT F.XXX, F.CCC, F.AAA, BBB FROM XXXX ...

  9. Python:序列的copy() 方法和 copy 模块

    转于:Python中copy和deepcopy中的区别 博主:assan 一.序列中的 copy() 方法 # 此方法为浅度复制:复制的数会随着被复制数的嵌套序列的元素的改变而改变: # 功能:将一个 ...

  10. vue-cli脚手架build目录中的karma.conf.js配置文件

    本文系统讲解vue-cli脚手架build目录中的karma.conf.js配置文件 这个配置文件是命令 npm run unit 的入口配置文件,主要用于单元测试 这条命令的内容如下 "c ...