代码改变世界

结对编程2 单元测试

2017-03-29 20:48  weihui  阅读(373)  评论(13编辑  收藏  举报

软件工程 结对编程2

(单元测试)

*这次博客的一个小目录

1.我和我的小伙伴的学号

2.项目开发的coding.net 地址

3.单元测试完成的五个部分

a.需求分析  b.设计测试框架, 模拟测试数据  c.小结与感受  d.复看代码的体会 e.再谈感受

4.描述结对的过程,提供非摆拍的两人在讨论、细化和编程时的结对照片

5.展示PSP

6.思考

 


 

1.我和我的小伙伴的学号

魏辉 201421123029   博客地址: https://home.cnblogs.com/u/weihui-01/

林青 201421123047   博客地址: http://www.cnblogs.com/lqwe/

2.项目开发的coding.net 地址

我的coding.net:  https://git.coding.net/weh/software-testing.git  

Git使用教程:http://www.cnblogs.com/hebau-may/p/6382743.html

git 使用的截图

3.单元测试完成的四个部分

a.需求分析:测试上有哪些详细的需求?

a.1单元测试应该测试程序中最基本的单元——如在java中的类,在此基础上可以测试一些系统中最基本的功能点。

a.2 要保证代码覆盖率。这样才能够使得整个单元测试更有意义。

a.3单元测试的要快,一个测试的运行时间是几秒,而不是几分钟。

a.4单元测试应该产生可重复,一致的结果。

a.5 单元测试必须和产品代码一起保存和维护。

 

b.设计测试框架, 模拟测试数据:

      (1) 请给出计算模块的测试用例及运行结果
      (2) 描述测试过程中遇到的问题以及解决的方案。
      (3) 请展示上面描述的单元测试的每个环节。

 (1) 请给出计算模块的测试用例及运行结果

 

①把运算的代码先封装到一个类中,然后使用junit自动生成一个测试用例(也可fork助教的用例)。自动生成的用例如下:

@Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testDnj() {
        fail("Not yet implemented");
    }

    @Test
    public void testGnj() {
        fail("Not yet implemented");
    }

    @Test
    public void testGetSum() {
        fail("Not yet implemented");
    }

 

通过测试发现是错误的,不能通过的。截图如下:

 

然后把测试用例改成与自己所封装的类(运算)匹配。如下:

@Test
    public void testIDnj() {
        calculator.Dnj(0, 1, 1, 2);
        assertEquals(3,calculator.getSum());
    }


    @Test
    public void testGnj() {
        calculator.Gnj(0, 0, 3, 4, 1, 4, 3);
        assertEquals(4,calculator.getSum());
        calculator.Gnj(0, 1, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
    }

 

测试结果如下:

 

②这里进行覆盖率的测试。

覆盖率测试教程链接:

http://blog.csdn.net/aotian16/article/details/7812751

http://www.open-open.com/doc/view/d9ce04653a1849deb77d1a70ffc51537

 

这个是刚刚改正后的test代码:

@Test
    public void testIDnj() {
        calculator.Dnj(0, 1, 1, 2);
        assertEquals(3,calculator.getSum());
    }


    @Test
    public void testGnj() {
        calculator.Gnj(0, 0, 3, 4, 1, 4, 3);
        assertEquals(4,calculator.getSum());
        calculator.Gnj(0, 1, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
    }

测试的结果是代码的覆盖率很低很低。低到让我头疼!!!不过经过仔细的思考,不难发现,是有一些代码确实通过我所列出的用例是无法测试到的。于是我便对test进行了更改。

 

更改后的test如下:

 @Test
    public void testDnj() {
        calculator.Dnj(0, 1, 2, 4);
        assertEquals(3,calculator.getSum());
        calculator.Dnj(1, 1, 1, 1);
        assertEquals(0,calculator.getSum()); 
        calculator.Dnj(2, 1, 1, 1);
        assertEquals(1,calculator.getSum());
        calculator.Dnj(3, 1, 1, 1);
        assertEquals(1,calculator.getSum());
         
    }  
    @Test
    public void testGnj() {
        calculator.Gnj(0, 0, 1, 1, 1, 1, 1);
        assertEquals(3,calculator.getSum());
        calculator.Gnj(0, 1, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());      
        calculator.Gnj(0, 2, 1, 1, 1, 1, 1);
        assertEquals(2,calculator.getSum());
        calculator.Gnj(0, 3, 1, 1, 1, 1, 1);
        assertEquals(2,calculator.getSum());
        
        calculator.Gnj(1, 0, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
        calculator.Gnj(1, 1, 3, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());      
        calculator.Gnj(1, 2, 1, 1, 1, 1, 1);
        assertEquals(0,calculator.getSum());
        calculator.Gnj(1, 3, 1, 1, 1, 1, 1);
        assertEquals(0,calculator.getSum());
        
        
        calculator.Gnj(2, 0, 1, 1, 1, 1, 1);
        assertEquals(2,calculator.getSum());
        calculator.Gnj(2, 1, 1, 1, 1, 1, 1);
        assertEquals(0,calculator.getSum());      
        calculator.Gnj(2, 2, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
        calculator.Gnj(2, 3, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
       
        calculator.Gnj(3, 0, 1, 1, 1, 1, 1);
        assertEquals(2,calculator.getSum());
        calculator.Gnj(3, 1, 1, 1, 1, 1, 1);
        assertEquals(0,calculator.getSum());      
        calculator.Gnj(3, 2, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
        calculator.Gnj(3, 3, 1, 1, 1, 1, 1);
        assertEquals(1,calculator.getSum());
        
        
    }   

 

 再测试一波,果然与预期一致,测试显示代码覆盖率为100%。欧耶!

 

 

③白箱测试

这个是低年级版本的运算程序的白箱测试:

 

这个是高年级版本的运算程序的白箱测试:

 

④黑箱测试:

修正后的输出截图:

 

⑤异常的处理 此处对除数等于0这种情况进行了异常的处理。

else if(a[b]==a[3])
    {
        if(d==0)
        {
            throw (new Yc());
        }
        else
            sum=(long) ((float)c/d);
    }

 

public class Yc extends Exception{
    public void Cs()
    {
        System.out.println("除数不为0");
    }
}

 

(2) 描述测试过程中遇到的问题以及解决的方案

①首先的问题就是单元测试到底是什么,到底是用来干什么的?

这个问题的解决我主要是通过看《构建之法》第二章和第十三章来解决,同时对于一些细节的问题是通过百度来具体看的。

②用junit自动生成的测试例子无法通过测试。

解决办法,就是查了一些资料,资料中谈到,生成的范例需要自己再加入一些封装的运算类的东西才能够真正的跑起来。然后我就照做了,通过对代码的再次深度解读,最终是写出了单元测试通过的代码。但是自己写的到底对不对,我就真的不太清楚啦。

③覆盖率低的问题。

覆盖率低,经过分析主要的原因在于test写的不够完整,由于不完整所以直接导致整个封装类只有部分代码会真正的使用到,所以后面我基于对问题的分析,解决了这个问题。

④黑箱问题。

一开始看完了第十三章就想做一个白箱、黑箱测试,然后在做黑箱测试的时候发现了问题,问题的解决主要是采用处理异常的办法。

⑤关于junit和eclemma的正确使用问题。

一开始接触这些插件,使用的时候经常出乱子。所以我是通过网络找了若干个教程,最后才得以顺利完成测试任务。

 

(3) 请展示上面描述的单元测试的每个环节。

①单元测试环节,这个环节本来是录制了一个完整的gif,奈何>10M 无法上传。那就简单的描述一下吧。

首先是要把测试的运算代码封装到一个类里,再者就是调用插件junit,这个是eclipse里面本来就有的,所以直接添加一下就可以啦。将JUnit4单元测试包引入到建立的项目(含有封装类):在该项目上点右键,点“属性”,进入后添加junit。在弹出的属性窗口中,首先在左边选择“Java Build Path”,然后到右上选择“Libraries”标签,之后在最右边点击“Add Library…”按钮,然后在新弹出的对话框中选择JUnit4并点击确定。生成JUnit测试框架:在Eclipse的Package Explorer中用右键点击该类弹出菜单,选择“New à JUnit Test Case”。之后系统会自动生成一个新类CalculatorTest,里面包含一些空的测试用例。需要将这些测试用例稍作修改即可使用。

 

 

 

②覆盖率测试,做这个测试的过程主要就是将eclemma插件加入到eclipse中,可以直接下载老师发在群里的安装包,然后解压到eclipse的home目录下。再更改eclipse的设置,使得界面工具栏出现这个插件的运行按钮即可使用。

 

③白箱、黑箱测试。

黑盒测试也称功能测试或数据驱动测试,它是在已知产品所应具有的功能,通过测试来检测每个功能是否都能正常使用,在测试时,把程序看作一个不能打开的黑盆子,在完全不考虑程序内部结构和内部特性的情况下,测试者在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数锯而产生正确的输出信息,并且保持外部信息(如数据库或文件)的完整性。黑盒测试方法主要有等价类划分、边值分析、因—果图、错误推测等,主要用于软件确认测试。“黑盒”法着眼于程序外部结构、不考虑内部逻辑结构、针对软件界面和软件功能进行测试。“黑盒”法是穷举输入测试,只有把所有可能的输入都作为测试情况使用,才能以这种方法查出程序中所有的错误。实际上测试情况有无穷多个,人们不仅要测试所有合法的输入,而且还要对那些不合法但是可能的输入进行测试。 
 白盒测试也称结构测试或逻辑驱动测试,它是知道产品内部工作过程,可通过测试来检测产品内部动作是否按照规格说明书的规定正常进行,按照程序内部的结构测试程序,检验程序中的每条通路是否都有能按 预定要求正确工作,而不顾它的功能,白盒测试的主要方法有逻辑驱动、基路测试等,主要用于软件验证。“白盒”法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。“白盒”法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。贯穿程序的独立路径数是天文数字。但即使每条路径都测试了仍然可能有错误。第一,穷举路径测试决不能查出程序违反了设计规范,即程序本身是个错误的程序。第二,穷举路径测试不可能查出程序中因遗漏路径而出错。
 
④异常处理。这个主要就是运用简单的异常处理办法进行处理的。不再多说。
 
 

 c.小结与感受:通过测试,是否有效发现了程序计算模块的问题,并给予改进?

c.1 通过测试一定程度上优化了程序设计模块,同时也让我更深入学习了自己写的代码,适当的增加了一些注释,这样代码的可读性就得到了提高。

c.2 通过测试发现了除数不能为0的问题以前没有很具体的考虑到,这次通过测试将这个错误找了出来,并进行了相应的处理,从而我也感觉到了单元测试的魅力,它能驱使我不断地提高自己代码的质量。

c.3 单元测试的方法也算是比较多的,具体测试的形式也是挺多的,这次测试后最大的感受就是需要更进一步的去了解和学习单元测试的方法和一些常用的工具,这样在以后实际使用的时候便可以达到事半功倍的效果啦。

 

d.在隔了一周之后再看之前的代码,是否更能体会到下面这些东西

      (1) 良好的设计
      (2) 编码规范
      (3) 必要的注释

 

d.1这周进行了单元测试,通过具体的多种测试,我发现了自己以前代码的一些问题,然后进行了修改和优化。

d.2通过这些修改和优化代码的编码更加的规范了,比如类名的设定、注释的编写等。这些细节问题的完善使得代码整体来看有了质的飞跃。

d.3通过测试我对于除数不能为0问题,异常输入问题进行了处理,由此整个运算模块的设计更显得设计合理。

d.4这次测试,我明白了注释很重要,但是并不是越多越好,所以对于注释,我也尽可能的优化(删繁就简)。如此还是挺好的。

d.5总的来说通过单元测试和修正,我更能体会到良好的设计、编码规范和必要的注释的重要性。同时在我的代码中也更多的体现了这些东西。

 

 

e.再谈感受:结对编程真的能够带来1+1>2的效果吗?通过这次结对编程,请谈谈你的感受和体会。

 e.1 通过两次结对编程作业,我对结对编程这种方式有了更为深刻的认识和理解。由于有了对于结对编程的一些了解和认识(通过上次的结对作业的具体实现过程我在与队友进行正式的工作前首先看了书本的相关内容,而后查阅网络上的关于合作的正确姿势的文章。读后开始行动。)如此有了一定理论的支撑,也有了上次结对作业的一些经验,这次真实的落地就更能起到事半功倍的效果啦。

e.2 这次的队友依旧是第一次的结对队友,相互熟悉,具体工作开展起来也比较顺畅。

e.3 这次编程我依旧是领航员的角色,我制定单元测试的相关计划,然后我们两个人一起去执行。期间最值得一提的就是一起学习单元测试网上的教程,一起尝试动手去做。碰到问题一起讨论。起到了很好的合作的效果。

e.4 这次结对作业我能更加深入的体会的结对编程的魅力,它让我提高了对代码可读性的要求,让我更具体的感受到编程不是一个人在战斗。如此我经过分析考虑觉得1+1在一定程度上确实起到了大于2的效果。虽然在一定的程度上结对的效果还没体现,但是我觉得这应该是我们的结对还没有达到熟练的程度,我们还需要努力。在以后的合作中,不断地提高默契,改正不足。不读那进步。

 

4.描述结对的过程,提供非摆拍的两人在讨论、细化和编程时的结对照片。

 结对过程:由于在一个宿舍,所以合作起来比较方便。有了上一次结对编程的基础,这次结对编程具体的完成上,我们做的更好了。我们在读完题后就制定了完成题目的计划。具体操作中互相配合,共同学习了单元测试的相关内容,然后一起去尝试单元测试的具体实现。遇到问题及时沟通和讨论。

 

 

5.展示PSP

 

 分析:经过这几次作业,我对于psp有了更加深刻和具体的体会和认识,它不仅是一个时间的记录、是自我完成情况与预期比较的直观表格,更是督促我在有限的时间里更快的完成任务的一个闹钟。此处估计大体上与实际情况出入很小,一定程度上说明了我对自身的认知水平有了一定的提高,与此同时也从侧面反映出我对项目(此次为单元测试)的预估能力也有了一定的提高,这是很值得欣喜的。学而不思则罔,思而不学则殆。只有不断的思考,不断地练习才能不断地进步。

 


 

6.思考

6.1用“汉堡包”的方式来评价一下我的小伙伴。第一层(先来一片面包):通过第一次结对后的提醒我的小伙伴有了很大的提高,做事的时候更懂得坚持,具体编程学习的时候更加的认真投入,而且合作的过程中很好相处,遇到问题都能通过讨论很轻松的解决。来点小提醒(再把肉放上):队友的执行力依旧有待提高,有时候有点拖延。希望能够在以后的学习和生活中养成今日事今日毕的习惯来,这将会收益终生的。最后再来一些建议(然后再来一片面包):希望队友在以后的学习生活中有问题要主动去问,遇到困难,不要退缩,勇往直前,只要你努力一定都是可以解决的。

6.2  这一段时间以来,软件工程课程采用写博客作业的方式进行考核。大家都普遍觉得任务比较重,大部分时间都是在做这个。确实如此,我自己也是,每周会花很长的时间在完成软件工程的作业上。不过我个人觉得这种模式还是很好的。我个人一直是喜欢具体做事的人,我认为即使我没在写博客,也不一定会用写博客的时间去做更有意义的事情。在力所能及的前提下多做一点对自己总是好的。我会在以后的学习中,尽可能的提高自己的工作效率!