第四周作业之wcPro核心模块的实现

第四周作业之wcPro核心模块的实现

一、基本任务:代码编写+单元测试

小组github地址

https://github.com/SkateCloud/wcPro

PSP表格

PSP2.1PSP阶段预估耗时(分钟)实际耗时(分钟)
Planning 计划 30 60
Estimate 估计任务需要多少时间 30 60
Development 开发 120 180
Analysis 需求分析 20 30
Design Spec 生成设计文档 20 30
Design Review 设计复审 20 30
Coding Standard 代码规范 30 10
Design 具体设计 30 50
Coding 具体编码 30 40
Code Review 代码复审 30 40
Test 测试 50 10
Reporting 报告 70 240
Test Report 测试报告 30 100
Size Measurement 计算工作量 20 60
Postmortem 总结 20 80
  合计 280 480

接口设计

  • 接口描述

本人负责的是核心模块,即对输入的文件读取后的结果进行单词排序并存入List结构中准备输出

  • 设计思路

对从输入模块获取的数据存入hashMap中,再将Map结构转变成List结构进行单词排序,为输出模块准备接口

  • 实现过程

先使用Map<String, Integer>结构对输入模块传来的数据进行存储.

 HashMap<String,Integer> words = new HashMap<>();
        String str = readFile(args[0]);
        {
            int state = 0;
            int beginIndex = -1;
            for (int i = 0; i <= str.length(); ++i) {
                char ch = i == str.length() ? ' ' : str.charAt(i);
                boolean isWordChar = ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '-';
                if (state == 0 && isWordChar && ch != '-') {
                    beginIndex = i;
                    state = 1;
                } else if (state == 1 && !isWordChar) {
                    String word = str.substring(beginIndex, i).toLowerCase();
                    words.put(word, words.getOrDefault(word, 0) + 1);
                    state = 0;
                }
            }
        }

由于外部存储机构使用的是Map.Entry<String, Integer>,不便于排序等操作,所以将map转化为List结构,进行排序

 List<Map.Entry<String, Integer>> list = new ArrayList<>();
        list.addAll(words.entrySet());
        list.sort((lhs, rhs) -> {
            int cmp = -lhs.getValue().compareTo(rhs.getValue());
            if (cmp != 0) return cmp;
            else return lhs.getKey().compareTo(rhs.getKey());
        });

测试设计

保证设计的测试用例应至少覆盖函数中所有的可执行语句,同时主要空数组、最差情况、词频排序、字母排序、两者混合等各种情况设计测试用例。

附件2截图

单元测试

使用测试脚本进行单元测试,过程如下

测试脚本运行截图

单元测试效果良好,没有报错

小组贡献

我们小组齐心协力, 攻克难关,积极讨论,指出问题,我认为我的小组贡献分是0.4

二.扩展任务:静态测试

1. 代码规范

我选择了代码风格规范中:断行与空白的{}行、分行、命名、下划线、大小写;

代码设计规范中:函数、错误处理、new和delete、类型继承,模块化

我的编程习惯与以上附录中所述规范大致相同。而在其他如代码审查等重要规范上有待提高。

2. 同组分析

我分析了自己的代码,缩进、断行风格整洁,命名简单明了,逻辑清晰易读,但在代码设计规范上,模块化不足,不易于进行团队的coding工作,经常在git操作上发生冲突.

最后决定将团队代码进行整合重构,重构任务由我完成,故最终贴出组长的重构代码

public class wordcount {
    public static void main(String[] args) {
        long t1 = System.currentTimeMillis();
        new wordcount().start(args);
        long t2 = System.currentTimeMillis();
        long dt = t2 - t1;
        System.out.println(("Elapsed " + dt + "ms"));
    }

    private void start(String[] args) {
        HashMap<String,Integer> words = new HashMap<>();
        String str = readFile(args[0]);
        {
            int state = 0;
            int beginIndex = -1;
            for (int i = 0; i <= str.length(); ++i) {
                char ch = i == str.length() ? ' ' : str.charAt(i);
                boolean isWordChar = ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '-';
                if (state == 0 && isWordChar && ch != '-') {
                    beginIndex = i;
                    state = 1;
                } else if (state == 1 && !isWordChar) {
                    String word = str.substring(beginIndex, i).toLowerCase();
                    words.put(word, words.getOrDefault(word, 0) + 1);
                    state = 0;
                }
            }
        }

        List<Map.Entry<String, Integer>> list = new ArrayList<>();
        list.addAll(words.entrySet());
        list.sort((lhs, rhs) -> {
            int cmp = -lhs.getValue().compareTo(rhs.getValue());
            if (cmp != 0) return cmp;
            else return lhs.getKey().compareTo(rhs.getKey());
        });

        try (FileWriter fout = new FileWriter("result.txt")) {
            int maxsz = Math.min(list.size(), 100);
            for (int i = 0 ; i < maxsz; ++ i) {
                Map.Entry<String, Integer> item = list.get(i);
                fout.write(item.getKey());
                fout.write(' ');
                fout.write(item.getValue().toString());
                if (i != maxsz - 1)
                    fout.write('\n');
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    private String readFile(String path) { // 读文件
        try {
            byte[] encoded = Files.readAllBytes(Paths.get(path));
            return new String(encoded, "UTF-8");
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

}

3. 静态代码检查工具

使用的是IDEA的插件Ant Build中的检错功能
Ant Build是一个Java自动化生成工具,其检错功能用来检查类或者jar文件,用来发现可能的问题。检测完成之后会生成一份详细的报告,借助这份报告可以找到潜在的bug.

检测范围

  • 常见代码错误,序列化错误
  • 可能导致错误的代码,如空指针引用
  • 国际化相关问题:如错误的字符串转换
  • 可能受到的恶意攻击,如访问权限修饰符的定义等
  • 多线程的正确性:如多线程编程时常见的同步,线程调度问题。
  • 运行时性能问题:如由变量定义,方法调用导致的代码低效问题

4. 扫描结果

扫描结果

检测结果在右上角,可以看出仅有少量警告,根据IDEA红线标注可发现大多是声明方式不是按照目前使用的java标准,没有发生内存泄露等问题.

5. 小组代码问题说明

  • 由于进行了整合重构,所以模块化程度降低,不易维护,但程序执行效率上升
  • 异常处理的不够全面,应该覆盖大部分的一场情况,以便于检查与调试

三. 高级任务:性能测试和优化

设计,评审,优化

选择10kb,50kb,182kb大小的txt文件进行测试,程序处理时长如下:

      输入输出:1ms,1ms,2ms

      单词统计:20ms,150ms,540ms

      词频排序:6ms,8ms,10ms

  单词统计时间与文件大小呈线性相关,其他两个模块占比较小,故程序性能主要受到文件大小影响。组内共同对代码结构和细节进行详细审查并与其他组程序对比,整理得到如下观点:

    1.整合重构是正确的,不仅增加了代码的可读性和规范性,还大幅增加了程序的性能

    2.将大部分功能模块聚集在一个类方法中,虽然会导致代码耦合度增高,不易于团队维护和再开发,但是减少了模块间相互调用的开销和随之产生的内存开销

小结

通过基本任务、扩展任务、到高级任务的完成以及中间遇到的许多困难,体现出了软件测试对于软件开发的重要性。在开发过程中,使用静态测试工具实时地检测自己的代码,可以改正自己不良的编程习惯,更能防患于未然,减少出现bug的可能;对自己的模块进行单元测试,可以保障自己代码的正确性,更是对其他开发成员和整个任务的负责,使软件开发能够一步一个脚印地稳定开展;对性能的分析与测试,能使软件的质量进一步提高,同事能总结开发经验,使自己设计的模块更加高效。

posted @ 2018-04-08 22:38  skatecloud  阅读(203)  评论(1编辑  收藏  举报