码迷,mamicode.com
首页 > 其他好文 > 详细

WordCountPro,完结撒花

时间:2018-04-07 17:46:01      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:sage   write   evel   eal   接口   需求文档   数组   项目需求   字符   

WordCountPro,完结撒花

软测第四周作业

一、概述

该项目github地址如下:
https://github.com/YuQiao0303/WordCountPro

该项目需求如下:
http://www.cnblogs.com/ningjing-zhiyuan/p/8654132.html
在此完成了基本任务和拓展任务。

该项目PSP表格如下:

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

基本任务

二、实现接口

这次任务设计的框架中,我们设计了一个类,类的结构如下:
(待续)
技术分享图片

经过讨论认为wcPro()相对较难,最终分工如下:

isInputValid() :商莹
wcPro() :余乔(我),雷佳谕。(结对编程)
output():蒋雨晨

其中,我和队友雷佳谕分到的wcPro方法需要完成的功能是,统计文本文件input中的单词和词频,将结果存入类的静态属性Info中。(Info声明如下:)

static TreeMap<String,Integer> Info = new TreeMap<String,Integer>(); `

采用结对编程的方式完成了该方法的实现。设计思路如下:

  • 与第二周相同,采用String类的split方法分割单词,将统计的单词和词频存入TreeMap类型的变量Info中。
  • 按行读取文件。根据需求,输入的文本文件中,所有可能出现的字符分为三种:字母、连字符、其他字符(包括数字和给出的常用字符表中的全部常用字符)。我们将其他字符作为分隔符,分割得到“潜在单词”(word)。
        String reg1 = "[\\s~`!#%\\^&\\*_\\.\\(\\)\\[\\]\\+=:;\"‘\\|<>\\,/\\?0-9]+"; 
        String words[] = line.split(reg1); 
  • 潜在单词中,可能出现“”(空字符串)和“---”(只含连字符的字符串)的情况。通过判断,直接丢弃改潜在单词。

for(String word: words){ if("".equals(word)||!word.matches(containLetter)){ continue; } ... }

  • 剩下的潜在单词全是需要统计的单词,但统计是需要去掉单词首位的连字符。例如遇到潜在单词“-night”,存入Info的应该是“night”。我们的处理方法是通过循环语句,找到潜在单词word中,第一个不是连字符的字符的坐标firstIndex(也就是第一个字母的坐标),和最后一个不是连字符的字符的坐标lastIndex(也就是最后一个字母的坐标)。然后利用subString方法得到最终要存的单词。

String containLetter=".*[a-z].*"; int firstIndex=0,lastIndex=word.length()-1; while(word.charAt(firstIndex)==‘-‘)//寻找第一个字母的坐标 { firstIndex++; } while(word.charAt(lastIndex)==‘-‘)//寻找最后一个字母的坐标 { lastIndex--; } word=word.substring(firstIndex, lastIndex+1);

  • 最后将统计结果写如Info中即可。
 if(!Info.containsKey(word)){ 
                   Info.put(word,1); 
               }
               else{ 
                   Info.put(word,Info.get(word)+1); 
               } 

于是即可得到wcPro()方法的完整代码:

static void wcPro(String input) throws IOException{
        
        /*将单词和词频存入info
         * 雷佳谕、余乔
         * */
        File file=new File(input); 
        BufferedReader br = new BufferedReader(new FileReader(file)); 
        String line = null; 
        //定义一个map集合保存单词和单词出现的个数 
        //TreeMap<String,Integer> tm = new TreeMap<String,Integer>(); 
        //读取文件 
        while((line=br.readLine())!=null){ 
           line=line.toLowerCase(); 

           //System.out.println(line);
           String reg1 = "[\\s~`!#%\\^&\\*_\\.\\(\\)\\[\\]\\+=:;\"‘\\|<>\\,/\\?0-9]+"; 
           String containLetter=".*[a-z].*";
           //String reg2 ="\\w+"; 
           //将读取的文本进行分割 
           String words[] = line.split(reg1); 
           for(String word: words){ 
               if("".equals(word)||!word.matches(containLetter)){
                       continue;
               }
              
               int firstIndex=0,lastIndex=word.length()-1;
               while(word.charAt(firstIndex)==‘-‘)//寻找第一个字母的坐标
               {
                   firstIndex++;
               }
               while(word.charAt(lastIndex)==‘-‘)//寻找最后一个字母的坐标
               {
                   lastIndex--;
               }
               word=word.substring(firstIndex, lastIndex+1);
               if(!Info.containsKey(word)){ 
                   Info.put(word,1); 
               }
               else{ 
                   Info.put(word,Info.get(word)+1); 
               } 
           } 

        } 

        br.close();
        
    } 

设计测试用例

针对结对编写的wcPro()方法的单元测试,是我和队友雷佳谕,分别独立完成的。我们各有一个测试类。

其中,我按照白盒测试和黑盒测试方法,共设计了34个测试用例。

白盒测试

这里采用独立路径测试的思想。

首先画出程序图。原本画出的程序图是这样的:

待续

我和队友画完图,才发现程序结构实在让人看不下去。于是将程序修改之后(也就是刚才展示的样子),才得到新的程序图:
(分支节点用黄色标出)
待续
可以看到,wcPro()方法的环复杂度为7,需要设计七个测试用例。
首先选择了主路径ABCEFGIKLNCAD
待续
之后分别改变A/C/E/G/I/L六个分支节点的判定结果,得到剩下六个独立的测试用例。
最终得到的白盒测试(路经测试)的七个测试用例情况如下:
待续

黑盒测试

wordCountPro到底如何进行黑盒测试,这个问题困扰了我很久。几次推翻重来,最后的考虑是这样的:

输入作为一个文本,每个字符都有很多中可能,文本长度不限,从而文本的内容组合有几乎无数种。

从需求的角度看,只含字母的可以算一类,一串字母首尾含连字符的可以算一类,一串字母中间含连字符的可以算一类,等等。

但是从黑盒测试的角度,假装自己完全不了解程序内部结构,我会非常担心程序能否真的按要求,无bug地把这些情况按照一类来处理。

最后我的选择是,将每个字符分成三类:字母、连字符、其他字符(含数字和特殊字符)。如果将文本长度置为三个字符,27个用例即可穷尽三类字符的所有排列组合,同时也不失一般性。这样测试,我会感到保险很多。
待续
但是仍然不觉得完全保险:程序真的能将数字和所有提到的特殊字符,都当做一类,进行正确处理吗?

于是还是加了最后一个大综合测试用例,其中包含所有需求文档中提到的常用字符:
待续
这样就得到了35个测试用例。

编写测试脚本

测试脚本乏善可陈,唯一值得一提的地方或许在于,我在测试类WCProTestYuQiao的Beforeclass方法中,重写了一遍测试用到的输入文件,从而更好地保证了测试的可移植、可重用性。

@BeforeClass
    public static void setUpBeforeClass() throws Exception {
        int n=35;
        String fileName[] = new String[n];
        String fileContent[] = new String[n];
        //给文件名赋值
        for(int i=0;i<n;i++)
        {
            fileName[i]="YuQiaoTestFile\\YuTest"+i+".txt";
            //System.out.println(fileName[i]);
        }
        //给文件内容赋值
        fileContent[0]="a";
        fileContent[1]="";
        ...

单元测试的结果与评价

几度重新设计用例,重新编写脚本,最终终于得到一条令人满意的green bar:
待续

测试质量

白盒测试的七个测试用例,完全符合独立路径测试的方法和思想,认为完成得很不错。

而黑盒测试部分,可以说我的等价类划分、测试用例设计都只是很大程度上运用了黑盒测试的思想,而非严格遵循其方法。

三种字符,27个用例,其中类似 “-a1”和“1-a”的文本内容,从需求的角度,程序应该作为同一等价类处理。这样的设计,从等价类划分的角度来说,是有冗余的。

但是这里我认为,“程序能否按照需求,对同一等价类内的输入进行等价处理”,本身就是风险的一大来源。因此完全按照需求进行等价类划分来测试,会让我感到风险太大;对不同输入的组合进行测试,结果更有保证。

测试的一大重点,在于低成本和低风险之间的平衡。

而对于wordCountPro这样的小程序,测试的成本和商品软件相比,是极低的(虽然对我个人来说还是下了很大功夫)。用35个用例所耗费的时间和精力,来换取一个更有保障的测试结果,我看性价比挺高,还是值得的。

也就是说,我认为我的测试质量不错。

被测模块质量

测试全部通过,可以认为被测模块较好地实现了功能需求。

小组贡献分

待续

拓展任务

考虑到基本任务和拓展任务分别要使用tag打标签,为了保证完成拓展任务时有事可做,我们在完成基本任务时,没有仔细参照代码规范;在拓展任务时,再对照规范进行检查。

规范阅读与理解

选择了阿里巴巴Java开发手册作为参考的规范。主要学习了其中的

  1. 命名风格
  2. 常量定义
  3. 代码格式
    三个部分。

阿里巴巴java开发手册
【强制】类名使用 UpperCamelCase 风格,但以下情形例外: DO / BO / DTO / VO / AO /
PO 等。
正例: MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例: macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从
驼峰形式。
正例: localValue / getHttpMessage() / inputUserId
【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例: MAX_STOCK_COUNT
反例: MAX_COUNT

这几条规则,可以使代码读者看到名称,就知道是类还是变量、方法、常量。

【强制】抽象类命名使用 Abstract 或 Base 开头; 异常类命名使用 Exception 结尾; 测试类 命名以它要测试的类名开始,以 Test 结尾。

这一条可以使代码读者看到类名就知道是否是抽象类、测试类。

【强制】类型与中括号紧挨相连来定义数组。
正例: 定义整形数组 int[] arrayDemo;
反例: 在 main 参数中,使用 String args[]来定义。
变量类型和名称区分得更清晰。

【强制】不允许任何魔法值(即未经预先定义的常量) 直接出现在代码中。
反例: String key = "Id#taobao_" + tradeId;
cache.put(key, value);

更易修改,增强了代码的可维护性。

【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行; 如果
是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行; 表示终止的右大括号后必须换行。

初见这句左大括号前不换行,我既惊讶又愤怒。

这种方式严重降低了代码的清晰性、可读性和可维护性。

没有清晰的缩进对齐,别说其他人,就是作者本人,编程和修改的过程也会徒增痛苦。

百度了一下,这条规则的主要好处在于,使代码更加紧凑,同样大小的界面可以看到更多行的代码。

行吧行吧你说的对。

队友代码分析

其实我们通过开三场同行评审会的方式,对三个大模块都进行了静态代码检查。

由于其他同学写的模块中,output()相对复杂,这里主要说说,在17161同学的output()方法中,我发现的问题。
待续
可以看到,代码中有许多地方不符合阿里巴巴java开发手册。
第107/111行的左大括号之前换了行;
第114/135行的右大括号后没换行;
第103/104行的类的注释没有采用javadoc规范;
第117行变量writefile命名不符合小驼峰规范;
第123行变量flag命名含义不清晰;
此外,第108行降序排序被写成了升序排列;
总体上注释很少,但由于方法功能简单,可读性仍然很强,不会造成理解障碍。

代码其他变量明明均符合规范,其他大括号换行合理。

静态代码检查工具使用

选择了阿里代码规约检查插件,地址如下:https://p3c.alibaba.com/plugin/eclipse/update
安装方法如下:
https://blog.csdn.net/huangzhe1013/article/details/78248036
截图
出现的问题已经在截图中列出,主要违反了大括号、命名和注释方面的规范。
其中最严重的问题在于if语句后没打大括号:

if(word.equals("")||!word.matches(containLetter))
                       continue;

小组总结

上面的截图没有扫描测试类,如果扫描整个小组含测试类的全部代码,结果如下:
全部问题
本次小组代码的主要问题,还是在大括号、命名、注释、个别函数使用、数组声明、魔法值等方面违反了代码规范。主要原因是开始编码前,没有仔细研读规范(以方便之后找错并修改)。现在有了这方面意识,也熟悉了常见的不合规范的错误,以后多注意,尽量不再犯。

后记

这次项目经历,让我印象较深的主要是一下两点:

1.先把设计做好,再开始实施。

已经写好测试脚本后,推到重来,重新设计测试用例,非常耗时。

2.一步一步完成一个项目,看着进度条一点一点前进,爽爽的。

3.做项目期间,室友竟然评论我:你最近吃饭怎么这么不积极。

一直信奉“良好的作息是生活高效健康,充满活力”的我,深感这样不好。

以后做项目,也好规律作息,抓紧时间,提高效率。

WordCountPro,完结撒花

标签:sage   write   evel   eal   接口   需求文档   数组   项目需求   字符   

原文地址:https://www.cnblogs.com/YuQiao0303/p/8733627.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!