软件质量与测试第四周作业——wcPro作业随笔

 

一.基础功能

1. Github地址

  小组github项目地址:https://github.com/Asfalas/wcPro

2.PSP表格

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

 20

 10

· Estimate

· 估计这个任务需要多少时间

 10

 5

Development

开发

 180

 150

· Analysis

· 需求分析 (包括学习新技术)

 10

 10

· Design Spec

· 生成设计文档

 10

 15

· Design Review

· 设计复审 (和同事审核设计文档)

 30

 18

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 20

 15

· Design

· 具体设计

 20

 25

· Coding

· 具体编码

 400

 450

· Code Review

· 代码复审

 60

 60

· Test

· 测试(自我测试,修改代码,提交修改)

 180

 400

Reporting

报告

 120

 100

· Test Report

· 测试报告

 30

 30

· Size Measurement

· 计算工作量

 10

 10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 50

 50

 

合计

 1150

 1350

 

3.接口实现

  我在项目代码编写过程中主要负责输出模块,包含了排序以及接口输出,所有功能模块封装在一个wcOutput类下

package com.SoftwareQualityAndTesting;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;

public class wcOutput

  和我对接的是张付俊,他将统计结果输出至一个Map,我就对Map进行遍历,并对value进行排序,其中涉及到参数的传递:

Map<String,Integer> tempMap= main.XXMap;

  在查阅了相关资料之后,而且建立在上一个作业中学到的读写文件功能的基础上,自己成功编写并运行了自己负责的功能模块并提交至小组github。

  参考资料:

    https://blog.csdn.net/zhu1qiu/article/details/71170850(对map进行遍历)

    https://blog.csdn.net/casularm/article/details/164877(map的性质)

  首先是排序,在算法课上学过,当下最优的选择莫过于快速排序:

public static void sort(Map.Entry<String,Integer> a[], int low, int hight) {
        int i, j;
        Map.Entry<String,Integer>tmp;
        if (low > hight) {
            return;
        }
        i = low-1;
        j = hight;
        tmp = a[hight];
        
        while (i < j) { 

            while((++i)<j&&!cmp(a[i],tmp)){}

            while(i<(--j)&&cmp(a[j],tmp)){}

            if(i<j){
                swap(a,i,j);
            }
        }
        swap(a,i,hight);
        sort(a, low, i - 1); 
        sort(a, i + 1, hight);

    }

  基于网上查找的资料,我选用了第二种遍历方式,第一种貌似存在向下兼容的问题,就没有使用:

Map.Entry<String,Integer>[]a=new Map.Entry[tempMap.size()];
int i =0;
for (Map.Entry<String, Integer> entry : tempMap.entrySet()) {  //遍历Map
    a[i] = entry;
    i++;
    }

  在遍历之后,只需要对map进行排序就可以,排序结果如实输出到目标txt文件上即可,先开辟空间创建FileWriter,再通过循环依次写入排序的结果。此处需要说明的是,在Oldbook大佬的提醒下,需要对输入情况进行讨论,数组长度小于100,和长度大于100的状况,因为循环的次数会有不同:

String outName ="result.txt";
        FileWriter writer = null;
        try {
            writer = new FileWriter(outName);
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        if (a.length<=SZ) {//词表少于100个
            for (Map.Entry<String, Integer> e : a) {    
                try {
                    writer.write(e.getKey() + " " + e.getValue() + "\r\n");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }else if (a.length>SZ){//词表大于100个
            for (i=1;i<=SZ;i++){
                try {
                    writer.write(a[i].getKey()+" "+a[i].getValue()+"\r\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        try {//清空缓存
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

  至此,我负责编写的模块以全部陈述完毕。

4.测试用例设计以及运行结果

  这次的测试用例使用JUnit进行编写,黑盒测试白盒测试都有涉及:以下是我设计的测试用例:

  具体代码实现选取部分贴在下面,因为我是每一个测试用例写一个类,因为清明时间的个人行程安排抽不开身,实在不好意思没有将它改写成统一的参数法,导致测试代码存在较大的冗余,不过在大佬的指导下,保证数量且保证时间的前提下完成了所需的单元测试模块。

public void testCmp1() throws Exception {
//TODO: Test goes here...
    Map<String, Integer> map1 = new LinkedHashMap<String, Integer>();
    map1.put("第一个整数值",1);
    map1.put("第二个整数值",2);
    Map.Entry<String,Integer>[]a=new Map.Entry[map1.size()];
    int i=0;
    for(Map.Entry<String, Integer> entry:map1.entrySet())
        a[i++] = entry;
    wcOutput.quickSort(a);
    assertEquals(false,wcOutput.cmp(a[0],a[1]));
}
@Test
public void testCmp2() throws Exception {
//TODO: Test goes here...
    Map<String, Integer> map1 = new LinkedHashMap<String, Integer>();
    map1.put("第一个整数值",2);
    map1.put("第二个整数值",1);
    Map.Entry<String,Integer>[]a=new Map.Entry[map1.size()];
    int i=0;
    for(Map.Entry<String, Integer> entry:map1.entrySet())
        a[i++] = entry;
    wcOutput.quickSort(a);
    assertEquals(true,wcOutput.cmp(a[1],a[0]));
}

  对比较功能模块进行逻辑覆盖中的判定/条件覆盖,属于白盒测试,因为这个类代码量并不大,所以测试类并不多,主要逻辑就是新建一个哈希表,填充value和key,在排序之后进行比较,判定结果正误。

 

@Test
public void testSwap1() throws Exception {
//TODO: Test goes here...
    Map<String, Integer> map2 = new LinkedHashMap<String, Integer>();
    map2.put("第一个整数值",1);
    map2.put("第二个整数值",2);
    Map.Entry<String,Integer>[]a=new Map.Entry[map2.size()];
    int i=0;
    for(Map.Entry<String, Integer> entry:map2.entrySet())
        a[i++] = entry;
    int j=a[0].getValue();
    wcOutput.swap(a,1,0);
    assertEquals(j,(int)a[1].getValue());
}

  对交换模块进行功能测试,同样也是新建一个哈希表,填充value和key,交换数值之后对比原数值检查是否已交换,这个方法同样十分简单,测试类也并不多。

public void testSort1() throws Exception {
//TODO: Test goes here...
    Map<String, Integer> map3 = new LinkedHashMap<String, Integer>();
    map3.put("第一个整数值",2);
    map3.put("第二个整数值",1);
    map3.put("第三个整数值",3);
    Map.Entry<String,Integer>[]a=new Map.Entry[map3.size()];
    int i=0;
    for(Map.Entry<String, Integer> entry:map3.entrySet())
        a[i++] = entry;
    int j =a[0].getValue();
    int k =a[1].getValue();
    int l =a[2].getValue();
    wcOutput.sort(a, 0, a.length - 1);

    assertEquals(j,(int)a[1].getValue());
    assertEquals(k,(int)a[2].getValue());
    assertEquals(l,(int)a[0].getValue());
}

  这个类是白盒测试中的判定/条件测试,针对原函数中sort方法进行覆盖测试,其中以下方法共同构成了逻辑覆盖的测试,对判定节点以及条件进行覆盖:

public void testSort2() throws Exception
public void testSort3() throws Exception 
public void testSort4() throws Exception
public void testSort5() throws Exception
public void testSort6() throws Exception
public void testSort7() throws Exception

  出于健壮性的考虑,我必然对这个方法使用了等价类测试,大致思路就是新建一个哈希表,输入基本值,进行排序并与预期排序结果比较,这里选取有代表性的罗列在下方,其他等价类测试的只列出类名,或者详见项目源代码:

public void testSort11() throws Exception {
//TODO: Test goes here...
    Map<String, Integer> map3 = new LinkedHashMap<String, Integer>();
    map3.put("第一个整数值",32);
    map3.put("第二个整数值",65);
    map3.put("第三个整数值",78);
    map3.put("第四个整数值",52);
    map3.put("第五个整数值",1);

    Map.Entry<String,Integer>[]a=new Map.Entry[map3.size()];
    int i=0;
    for(Map.Entry<String, Integer> entry:map3.entrySet())
        a[i++] = entry;
    int j =a[0].getValue();
    int k =a[1].getValue();
    int l =a[2].getValue();
    int m =a[3].getValue();
    int n =a[4].getValue();
    wcOutput.sort(a, 0, a.length - 1);

    assertEquals(j,(int)a[3].getValue());
    assertEquals(k,(int)a[1].getValue());
    assertEquals(l,(int)a[0].getValue());
    assertEquals(m,(int)a[2].getValue());
    assertEquals(n,(int)a[4].getValue());
}
public void testSort10() throws Exception
public void testSort9() throws Exception
public void testSort8() throws Exception 


  

  最后是对整个输出类进行测试,这里主要采用了边界测试,具体方法是自动生成大小为99,100,101的哈希表,对其执行output方法,并使用之前的行数统计方法,统计输出文件的行数,最后预期结果是大小小于100的哈希表对应的result.txt行数即为哈希表大小,大于等于100的哈希表对应的result.txt行数都为100,以下是我的测试代码,同样的,选取有代表性的粘贴,其他等价类测试的只列出类名,或者详见项目源代码:

public void testOutput3() throws Exception {
//TODO: Test goes here...
        int ST = 100;

        Map<String, Integer> map5 = new LinkedHashMap<String, Integer>();
        for (int i = 0; i <= ST; i++) {
            map5.put("Love Potion No." + i, i);
        }
        wcOutput wco = new wcOutput();
        wco.output(map5);
        BufferedReader reader = null;
        int res = 0;
        reader = new BufferedReader(new FileReader("result.txt"));
        String str = null;
        while ((str = reader.readLine()) != null) {
            ++res;

        }
        assertEquals(100, res);
    }

/*边界测试**/
public void testOutput1() throws Exception 
public void testOutput2() throws Exception 
/*等效类测试**/
public void testOutput4() throws Exception 

  以上就是我所有的测试类的设计思路及其说明。

 

5.测试结果评价

   

  测试结果如上图,output类的测试可能耗时会多一些,因为涉及到大量创建新的哈希表,在调用output类时同时也会排序,所以会消耗不少时间,在这25个测试类 之中,包含了判定/条件覆盖,等价类测试,语句覆盖,边界值测试等,可以看出,我编写的方法在逻辑层面基本未发现错误,值得小小的肯定一下。

 

6. 小组贡献

   根据小组讨论结果,小组贡献分大致为 17046-0.27分、17043-0.26分、17053-0.25分、17049-0.22分。

 

二.扩展功能

1.开发文档的选择与说明

     我们在开发过程中选择了《阿里巴巴Java开发手册》,通过老师在博客中发布的链接进行下载:https://yq.aliyun.com/attachment/download/?id=4942

  并且可以了解开发手册对应插件在IDEA上的应用:                               https://yq.aliyun.com/articles/225187spm=5176.10695662.1996646101.searchclickresult.6ff77f392uUgs1

 

2.同学的代码问题

   我负责检查孙帅(17043)的代码,可以看出,作为第一次进行代码检查的同学,他的编码习惯还是相当好的,毕竟我的编码检查出了14个错误(逃),我们都存在最后一个问题,就是类名的驼峰命名法;同样的我们都会存在包名的问题,都缺少了创建者信息,他只有一处使用了行尾注释,这非常好,说明他编码思想成熟,技法老道;唯一值得拿来提的就是“魔法值”的问题,即未定义的出现在代码中的常量。这个可以通过定义final变量解决。总而言之,孙帅的编码习惯属于特别好的那种。

3.代码检查工具及说明

   我们使用的是“alibaba java coding guidance”插件,可以通过idea直接下载使用,注意保持网络畅通(血的教训)。路径:setting-plugin-Browse Repositories-search

 

4.代码存在的问题

 

   我的代码还是很菜的,在java中数组规范是[]a,我却一直沿用c和c++的a[],最后改代码时加到手疼;可怕的是我的问题不仅如此,在for循环中我没有添加大括号,这点我真的记住了,怕了,手酸了;自己一直以来都使用的是行尾注释,现在才知道这种方法十分耗时间,没有快捷键,而且十分不美观,以后我会使用/*  **/型注释的。

 

5.小组存在的问题

  我们小组的问题还是挺严重的,这是远超个人问题的问题,我们没有使用UpperCamelCase风格作为类名,导致我在修改自己编写的输出及排序类时,因为重复调用编写的WcOutput类,25个测试方法每一个都要调用一次类名导致手都改断了,包名规范到还好,修改的并不多,不过仍需要注意;再就是在自己的代码下方添加自己的ID,这也是一件看起来十分具有职业精神的一件事,综上,大致就是我们小组共同的问题。

 

三.高级功能

1.测试数据集设计思路

   使用文件大小比较大的数据集来对本程序进行压力测试。我使用了英文的电子书籍《了不起的盖茨比》作为构造测试集,分别构造出了大小为500k,1m,2m,4m,8m,16m的数据集,同时使用了参数化方法对Main函数进行集成的多次测试,观察运行时间。

 

2.优化前性能指标

  程序的大小以及对应的时间消耗

 

3.同行评审过程

  小组成员:张付俊(U201517046)、孙帅(U201517043)、张瑞祺(U201517049)、文宇凡(U201517053)

  人员角色分工:张付俊(作者、讲解员)、孙帅(作者,评审员)、张瑞祺(作者,主持人)、文宇凡(作者、评审员)

  评审目的:确保要发布质量可靠的代码,发现各种类型的错误,提高代码质量、规范性、一致性和可维护性,提高代码效能。

  评审意见:

  孙帅:主要对于程序的代码规范角度与部分功能模块角度提出意见

  文宇凡:主要对于代码的功能实现角度提出意见

  评审结论:

  孙帅:(1)代码注释部分较少。可读性较差。

             (2)针对输出测试类方法代码存在大量冗余,需要改进。

  文宇凡:

             (1)将输入字符串传入核心处理模块导致两遍扫描文本,可能会使效率下降,可以一边读文本一边进行排序工作。

             (2)代码规范性存在许多问题需要改进。

  总体结论:代码需要作者做进一步改进

  本次评审的不足:

                  (1)由于时间较为紧凑,部分细节的评审并未做到面面俱到。

                  (2)因为代码量较少,评审内容有限,不能发现作者的隐藏问题。

 

4.测试后得到的结论

   在控制台运行截图如下

  不难发现,我们小组编写的软件可以在较短时间完成对较大文件的检索与阅读,图中[0]~[5]对应的依次是500k,1m,2m,4m,8m,16m等大小的txt文件。

 

5.优化思路及其指标

  优化思路如下:可以对一边对文本进行按字符读取,一边进行单词判断统计等功能,最后使用优化的随机快速排序算法(或者堆排序,oldbook说对java而言,堆排序更快)对容器进行排序,因为时间有限,优化尚未完成。

 

6.附加功能

  我们完成了图形界面,就像上一个作业一样,命令行输入-x就可以调出图形界面:

 JFileChooser jfc=new JFileChooser(".");
                 int returnVal = jfc.showOpenDialog(null);
                 if(returnVal == JFileChooser.APPROVE_OPTION)
                 {
                     //获得打开的文件
                     inputFile = jfc.getSelectedFile().getAbsolutePath();
                 }

 

6.总结说明

  自己作为一名程序员真的还有很多不足的地方,在之前做课设,大家都是用U盘,QQ群互相发送文件,并进行汇总,可这一次,单是github上的fork都让我学了半个小时,感谢小组成员的远程协助,本人愚钝,让他们费心了,以后会多使用github进行项目管理,毕竟这才是办公的趋势。而且越发意识到学习能力的重要性,需要更快速的学习一个新的框架,并熟练应用。然后需要说明的是,自己是在是不擅长使用github进行项目管理,在commit了第一次的输出类后,因为后续的更新,我发现我的fork还停留在之前的5次记录上,而非彼时的13次,所以我重新clone了新的代码,删掉了之前的fork,这也导致我的本地库及其混乱,后续编写的WcOutputTest类久久不能push,只能在最后时候发给组长张付俊让他帮我commit到他的分支,实属无奈,恳请老师和助教谅解。这是我当时发送的截图:

 

 7. 参考资料

    https://blog.csdn.net/zhu1qiu/article/details/71170850(对map进行遍历)

    https://blog.csdn.net/casularm/article/details/164877(map的性质)

    https://www.zhihu.com/question/21682976(github push和fork的使用)

    https://yq.aliyun.com/articles/225187?spm=5176.10695662.1996646101.searchclickresult.6ff77f392uUgs1(idea上使用代码规范插件)

 

转载于:https://www.cnblogs.com/ephemeral-no9/p/8720265.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值