结对编程2---单元测试
团队队员:201421123043 邱文鑫 + 201421123045 念其锋
码市的地址链接:https://git.coding.net/qwx_hh/Test.git
一、背景介绍
1.什么是单元测试?
在《构建之法》课本的第二章对于“单元测试”有如下的解释:绝大部分软件都是由多人合作完成的,大家的工作相互有依赖关系。最典型的例子就是,某人负责的模块的功能被其他人调用。软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化。如何能让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证呢?这时候就需要单元测试来解决这个问题。
2.为什么需要单元测试呢(需求分析)?
单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。
在一般情况下,一个功能模块往往会调用其他功能模块完成某项功能,如业务层的业务类可能会调用多个DAO完成某项业务。对某个功能模块进行单元测试时,我们希望屏蔽对外在功能模块的依赖,以便将焦点放在目标功能模块的测试上。这时模拟对象将是最有力的工具,它根据外在模块的接口模拟特定操作行为,这样单元测试就可以在假设关联模块正确工作的情况下验证本模块逻辑的正确性了。
单元测试的意义主要有以下几点:
(1)减少bug
一个机器,由各种细小的零件组成,如果其中某件零件坏了,机器运行故障。必须保证每个零件都按设计图要求的规格,机器才能正常运行。一个可单元测试的工程,会把业务、功能分割成规模更小、有独立的逻辑部件,称为单元。单元测试的目标,就是保证各个单元的逻辑正确性。单元测试保障工程各个“零件”按“规格”(需求)执行,从而保证整个“机器”(项目)运行正确,最大限度减少bug。
(2)快速定位bug,减少调试时间
如果程序有bug,我们运行一次全部单元测试,找到不通过的测试,可以很快地定位对应的执行代码。修复代码后,运行对应的单元测试;如还不通过,继续修改,运行测试.....直到测试通过。
对于Android项目,要测试某个功能点,不用单元测试的话,必须运行在真机、模拟器上,慢慢debug找到问题点。运行程序到真机,快则半分钟,慢则几分钟。junit只需在本地运行即可,就几秒的事(robolectric需要十几秒)。有时,写那个功能模块的员工已离职,APP运行出错(逻辑错误,非crash or exception),你根本就不知道调试哪个类。如果离职的员工之前写了单元测试,运行一下立马就找到问题点了。单元测试大大减少调试时间,从而达到节约时间成本的效果。
(3)提高代码质量
- 由于每个单元有独立的逻辑,做单元测试时需要隔离外部依赖,确保这些依赖不影响验证逻辑。因为要把各种依赖分离,单元测试会促进工程进行组件拆分,整理工程依赖关系,更大程度减少代码耦合。这样写出来的代码,更好维护,更好扩展,从而提高代码质量。
(4)放心重构
重构,每个开发者都会经历,重构后把代码改坏了的情况并不少见。以往,写完一个框架,运行APP,没什么问题,完事。由于最初的框架并不是你写的,可谓牵一发动全身,你改1个方法导致整个框架运行失败....
如果你有单元测试,情况大不相同。写完一个类,把单元测试写了,确保这个类逻辑正确;写第二个类,单元测试.....写100个类,道理一样,每个类做到第一点“保证逻辑正确性”,100个类拼在一起肯定不出问题。你大可以放心一边重构,一边运行APP;而不是整体重构完,提心跳胆地run。
3.怎样才算是一个好的单元测试呢?
(1)单元测试一个在最基本的功能/参数上验证程序的正确性;
(2)单元测试必须由最熟悉代码的人(程序的作者)来写;
(3)单元测试后,机器状态保持不变;
(4)单元测试要快(一个测试的运行时间是几秒钟,而不是几分钟);
(5)单元测试应该产生可重复、一致的结果;
(6)单元测试应该覆盖所有代码路径;
(7)单元测试应该集成到自动测试的框架中;
(8)单元测试必须和产品代码一起保护和维护。
二、设计测试框架,模拟测试数据
1.请给出计算模块的测试用例及运行结果,展示单元测试的每个环节
以下的这次计算模块我们写在同一个模块当中,但是测试的时候我们是分开测试的,具体如下:
(1)整数的除法测试:
(2)分数的除法测试:
(3)整数的加法测试
(4)分数的加法测试
(5)整数的减法测试
(6)分数的减法测试
(7)整数的乘法测试
(8)分数的乘法测试
(9)分数的覆盖率测试
(10)整数的覆盖率测试
2.描述测试过程中遇到的问题及解决方案
(1)对代码测试几乎不了解,在插件的安装上花费了很多时间,特别是代码覆盖率这一块。具体命令并不熟悉,花了时间研究了基础操作,基本上都是通过百度来获得解决的办法;
(2)原本计算的类包含了随机数选择、分数计算与整数计算这三个,所以刚刚知道实验要求的时候我们无从下手。后来经过我们的讨论之后,还是决定将原先的一个类拆分成三个类,然后把其中的分数计算类和整数计算类分别摘出来测试,这也给我们带来了较大的工作量;
(3)因为在原先的类中,取值已经避免了0当除数与分子的产生,所以没有必要测试这两种情况的异常报错。
(4)当我们在进行分数运算的时候,我们发现有的时候结果本应该显示成整数,但是程序运行的结果却是假分数,这不符合化简的要求,所以我们添加了几句代码,使得当分子与分子与分母的公约数相除等于1或者-1时,输出分母除分子,即从假分数转换成整数。
三、关于结对编程
1.使用结对编程模式的感受
这是我们第二次使用结对编程的合作模式,在我们还没有接触结对编程的时候,我们都认为两个人一起做一个项目,就应该是一个人负责实现这几种功能,另一个人负责实现另外几种功能,最后再将这些功能合并到一起,就形成我们俩一起合作完成的项目。幸亏有了第一次结对编程的经验,我们这次一开始就找到了自己“驾驶员”和“领航者”的定位,两个人同时坐在同一台电脑前,一个人敲代码另一个帮忙复审和提建议,监督一下有没有什么错误,一段时间后再对调角色,循环往复。这次结对编程与第一次结对编程的感觉不同,具体有以下几点:
(1)、当我作为“领航员”的时候,我就坐在我队友的旁边看着他敲代码(我们俩就是上下铺,电脑桌也就在隔壁,所以异常方便),他经常嘴上念的是正确的代码,敲上去的时候却敲成另外一种名称的代码,还好我就盯着他敲,及时指出了这个低级错误,不然他一个人的话可能要浪费很多时间才能找出这个问题;
(2)、当我们在结对编程的时候,只要对方遇到问题,都不用解释问题的前因后果,我们就能一下子知道对方指的是什么,这就是结对编程给双方带来的对互相编程思路的熟悉度,这也是以前那种各做各的的模式所体验不到的感觉;
(3)、我们两个人在结对编程的时候,还是遇到了一些我们俩都无法解决的问题,不过这种感觉跟自己一个人遇到难题时的感觉完全不一样,竟然有一种“完全不虚,我们迟早会解决”的蜜汁自信,可能这就是两个人的力量与一个人力量的差别。
2.给我队友的“汉堡包”
(1)、我们两个人本来就是很亲密的舍友,但在宿舍一般是比较了解对方的生活习惯和课余时间的兴趣爱好,通过这次的结对编程,让我在宿舍看到了他“学霸”的那一面,他打起代码来跟平时的他完全不一样,整个人沉浸在发现问题和解决问题的过程当中,让我对他“肃然起敬”,对他的专业技能也是钦佩不已;
(2)、我们在编程过程中经常遇到很多问题,是很多我们从来没有学过的问题,我往往都手足无措,而他却很沉着,精通各种查找资料的途径,不管是博客还是贴吧,他总能找到他需要的资源,这一点也是让我钦佩不已的;
(3)、不过在编程的过程我也发现了他的一些“bug”,他的英语水平较低,所以在写代码过程中经常出现英语拼写错误导致报错,这一点我在当“领航员”的时候见识过了非常多次,希望他能在课余时间多提高一下自己的英语水平,这对编程技术会有一定的提高。
3.结对编程照片
四、一周之后看代码
1.良好的设计
一开始的设计真的很重要,一开始的设计可以多花一点时间,这叫“磨刀不误砍柴工”,否则会出现很多的麻烦。比如一开始设计的时候,没有用字符串来封装式子,导致在主函数中,要对输入的字符串进行各种拆分各种判断,导致逻辑结构不清晰,代码冗余大。所以这一点的改进使得后续的一些函数编写容易多了。
2.编码规范
我们的编码规范在第一次结对编程的时候就定好了,在后面有添加变量的时候我们会立即跟对方通气,所以我们在一周之后再看代码的时候,只要对照着之前我们签订的代码规范文档来看,就可以很快地看懂一周前的那些代码,从而节省了很多时间。
3.必要的注释
注释这方面我们俩做得还是有点少,我们一般都会在宿舍直接向对方提出来,有的时候大家会听完就忘了,比如一周后往往记不起之前当面说的那些注释,所以把一些注释记录下来还是非常有必要的,也可以节省一些时间。
五、PSP展示
PSP2.1 |
personal sofware process stages |
time(%)senior student |
time(%) |
planning |
计划 |
10 |
15 |
estimeate |
估计这个任务需要多少时间 |
200 |
320 |
development |
开发 |
15 |
20 |
analysis |
需求分析 |
20 |
10 |
design spec |
生成设计文档 |
20 |
15 |
design review |
设计复审 |
15 |
30 |
coding standard |
代码规范 |
10 |
10 |
design |
具体设计 |
30 |
60 |
coding |
具体编码 |
100 |
200 |
code review |
代码复审 |
10 |
20 |
test |
测试 |
50 |
100 |
reporting |
报告 |
40 |
50 |
|
测试报告 |
15 |
10 |
|
计算工作量 |
5 |
10 |
|
并提出过程改正计划 |
10 |
5 |
六、小结与感受
1.对单元测试的步骤和过程还是很不理解,所以上网查资料的过程中花了大量的时间,这也让我看出来了自己还存在着许多的不足,还是需要继续深入学习Java的知识和eclipse软件的使用,这样子以后做项目就可以节约不少的时间;
2.虽然我和队友每天都在沟通,但有时候对他写代码的逻辑结构还不是很理解,这一点增加了单元测试的难度,以后要说好在写的时候要边敲代码边把自己的想法说出来,这样子大家会更加理解互相的想法;
3.经过这次的单元测试我发现只有自己写的代码测试的时候才会比较有头绪,如果是队友写的有可能会出现懵逼的情况,所以还是推荐谁写的代码谁来做测试。