欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第四周作业

程序员文章站 2024-03-15 18:03:18
...

项目地址

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语言的特性,相同的代码,运行次数越多,执行速度就会越来越快。

结论

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