第四周作业

项目地址

https://github.com/cosensible/WordCountPlus

PSP表格

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

接口实现

我负责的模块功能是输出控制。它将countWordFrequency()函数统计得到的单词词频结果写入到指定文件夹中。该接口主要处理以下问题:

  • 当得到的单词词频统计结果中没有记录时,程序没有记录可以写,该函数可以直接返回。
  • 当文件已经存在但是不可写时,程序无法写入结果,该函数直接返回。
  • 当文件不存在时,根据提供的文件名参数创建新的文件用以记录结果。
  • 初始化FileWriter和BufferedWriter。
  • 循环读取单词词频统计结果,写入指定文件流,并且统计写入记录的数量。
  • 当数量达到100,停止写入并返回。
  • 最后,关闭文件流。

以下是该函数的头部:

    public static int write(
        final String filePath, 
        final String[] contents, 
        final boolean append);

接口流程图:

上图中最后那个条件应该是:"num>=100或读到contents末尾"。

测试用例设计

白盒测试

为了对接口进行白盒测试,将以上给出的流程图改画为程序图如下:

图中有四个判定节点,只需设计五个测试用例。

路径 测试用例 预期输出 实际输出
A->B->D->E->F->G->H->C contents有一条记录,文件不存在 创建文件,返回1 创建文件,返回1
A->B->D->E->F->G->H->G->H->C contents有两条记录,文件不存在 创建文件,返回2 创建文件,返回2
A->B->D->E->G->H->C contents有一条记录,文件存在且可写 返回1 返回1
A->B->D->C contents!=null,文件存在但不可写 返回0 返回0
A->B->C contents==null 返回0 返回0

黑盒测试

该接口结构如下:

public static int write(
	final String filePath, 
    final String[] contents, 
    final boolean append);

据此,可以划分以下几个等价类测试:

等价类 说明
等价类1 结果记录集 contents 为空,返回0;
等价类2 contents!=null,路径对应的文件存在但不可写,返回0;
等价类3 contents!=null,路径对应的文件存在且可写,记录结果并返回num;
等价类4 contents!=null,路径对应的文件不存在,创建新文件记录结果并返回num;
等价类5 append=true,向记录结果的文件以追加方式写入记录。

单元测试结果

单元测试脚本

以下是部分测试脚本代码:

该测试脚本采用Junit4测试框架编写。

运行截图


分析以上单元测试结果,可以看出整个测试过程用了251ms,测试的效率比较高。另外,该测试覆盖度很高,考虑到了各种可能发生的情况。因此,该接口的可靠性得到了保证。
要是还想要提高测试类的运行速度,可以将全部的测试用例写在一个函数里面,经过测试,这种方法的运行速度为78ms,速度有很大提升。

扩展任务:静态测试

参考规范

阿里巴巴Java开发手册

对组员17139的代码规范分析

public class WordFrequencyCountUtil {
    public static String[] countWordFrequency(String[] resultContents){
        Map<String,Integer> resultMap=new TreeMap<String,Integer>();

        for(String content:resultContents){
            //按照规则,找出每行中,形如abc(-ab)*这样的单词
            String regex="[a-zA-Z]+(-[a-zA-Z]+)*";
            Pattern pattern=Pattern.compile(regex);
            Matcher matcher=pattern.matcher(content);
            while (matcher.find()){
                input(content.substring(matcher.start(),matcher.end()),resultMap);
            }
        }

        //对resultMap按照指定的规则进行排序
        List<Map.Entry<String,Integer>> list=new ArrayList<>(resultMap.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if(o1.getValue()<o2.getValue())
                    return 1;
                if(o1.getValue()>o2.getValue())
                    return -1;
                return o1.getKey().compareTo(o2.getKey());
            }
        });

        //将排好序的结果存入results中
        String[] results=new String[list.size()];
        int index=0;
        for(Map.Entry<String,Integer> entry:list){
            results[index++]=entry.getKey()+"  "+entry.getValue();
        }
        return results;
    }

    private static void input(String s,Map<String,Integer> map){
        s=s.toLowerCase();
        if(map.containsKey(s)){
            map.put(s,map.get(s)+1);
        }else
            map.put(s,1);
    }

    public static void main(String[] args){
        String[] result = WordFrequencyCountUtil.countWordFrequency(new String[]{"int", "int-main ni int'int"});
        for(String i : result)
            System.out.println(i);
    }

}

1.《阿里巴巴Java开发手册》中指出:【强制】if/for/while/switch/do 等保留字与左右括号之间都必须加空格。这样的风格让关键字更加突出,便于程序的阅读。显然,这位同学没有注意到这方面,暂且相信他以后是会改正的。
2.《阿里巴巴Java开发手册》中指出:【强制】任何运算符左右必须加一个空格。说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号、三目运行符等。同样的,这样的代码风格更便于阅读。显然,这位同学对这种规范还不知道,或者知道了但是不愿遵循,希望他以后能坚持下来。
3.《阿里巴巴Java开发手册》中指出:【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
这位同学在大多数情况下做得很好,但是在某些地方仍然做的不够好,应该是借助了IDE的帮助。希望他以后好好改进。
4.《阿里巴巴Java开发手册》中指出:【推荐】 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。这位同学先定义了一个public方法,后定义了一个private方法,又定义了一个public方法,显然没有注意到这个问题。
5.另外我觉得他的测试方法取名太随意了,直接使用test1,test2...这样的测试方法命名会给代码使用者带来很大的阅读障碍,因为他们很难知道代码编写者的意图,所以很难理解,会给测试造成较大影响。

@Test
public void test1() throws Exception {
    String[] result = WordFrequencyCountUtil.countWordFrequency(new String[]{"int"});
    assertEquals("int  1", result[0]);
}

@Test
public void test2() throws Exception {
    String[] result = WordFrequencyCountUtil.countWordFrequency(new String[]{"int int"});
    assertEquals("int  2", result[0]);
}

对自己代码静态检查

使用工具

静态扫描截图

可以看到,这个工具实在是太强大了,所有违背规范的地方都能够找出来,并显示链接让我们精确定位并且提供一键修改,非常方便。可以看出,代码主要的问题在于注释、命名规则以及符号前后的空格没有遵循规范,还有一些变量应该加上对应的关键字修饰符。

代码风格改进

public class FileUtilWriteTest {

    private FileUtil fileUtil;
    @org.junit.Before
    public void setUp() throws Exception {
        fileUtil=new FileUtil();
    }

    @org.junit.After
    public void tearDown() throws Exception {
    }

    @Test
    public void testNullContents() {
        //测试第二个参数 contents==null 时程序返回0
        final String filePath = "";
        final String[] contents = null;
        assertEquals(0, fileUtil.write(filePath, contents, false));
    }

    @Test
    public void testFileCanNotWrite() {
        //测试当文件存在但不可写时返回0
        final String filePath1 = "E:\\JavaProjects\\WordCountPlus\\src\\test\\test.txt";
        final String[] contents1 = {"import  3", "java  3"};
        File file = new File(filePath1);
        file.setWritable(false);
        assertEquals(0, fileUtil.write(filePath1, contents1, false));
    }
    ...
}

这里主要将一些错误的命名规则改正过来,将仅在类内部使用的变量添加private关键词修饰。这样一看,代码的命名显得异常统一,更加方便阅读。最重要的是,在小组内部达成了一致的意见,方便以后的合作。

重新运行单元测试

发现整个模块测试的运行时间变为126ms,相比之前提高了很多。这也许是因为程序运行了很多遍的原因,因为根据Java语言的特性,相同的代码,运行次数越多,执行速度就会越来越快。

结论

组内主要问题在于注释、命名规则以及符号前后的空格没有遵循规范,还有一些变量应该加上对应的关键字修饰符。另外,还有一些数据结构的使用方法不够规范,某些设计模式的运用不够熟练。经过这次代码规范的分析,整个小组人员认识到了自己在代码规范方面不够重视,以及这样做带来的代码缺陷,以后会尽最大努力编写满足规范的代码!

posted @ 2018-04-08 22:47  chungen  阅读(150)  评论(0编辑  收藏  举报