文章目录
测试驱动编程(3)进阶单元测试(下)
示例实战
接收同事的需求
你的同事正在开发一个远程控制轮船的程序,他已经完成了一部分工作,但是他休假去了, 现在任务交给了你。你的同事是一个TDD的践行者,你接下来要在他完成的工作基础上继续开发
下图是你同事设计的几个主要的类:
- Ship:表示轮船,目前没有任何方法,继续要迭代的地方
- Point:表示二维坐标
- Direction:代表方向的枚举类以及左右转弯的方法
- Planet:地球,轮船航行的地方,包含最大的航行坐标点以及分布了哪些障碍物设置
- Location:轮船当前方位,包含所在的坐标以及当前的行驶方向,可以前进后退、进行航行
下面是你同事已经完成的测试验证方法,所以请你放心的改造下去
方向测试类
轮船行驶范围(地球)测试类
二维坐标测试类
方位(包含方向与二维坐标)测试类
控制方向和坐标参考系如下:
特别要注意的是地球是圆的,起点和终点是重叠的。例如:往x轴最远处前进将回到x=1的坐标点
开始迭代需求
上面看到同事之前写的代码所有测试经过都是绿灯,我们可以放心的进行后面的需求迭代了
故事迭代1
我们需要给定轮船的起始位置以及方向
因为每次控制轮船的提前肯定是要有一艘轮船,所以在每个测试方法前都应该需要一艘船,我们把它放在@BeforeEach注解的方法里
Ship默认只有无参的构造函数所以报错了,这也是正常的
红-绿-重构
的
红
阶段,接下来我们进入
绿
阶段
写一个测试方法测试下
故事迭代2
轮船可以前进或后退
在编写轮船可以前进后退的时候,我们是不是要编写各个方向的前进和后退测试方法呢?类似下面的
该测试方法测试的是轮船往北移动,Y轴的坐标将加1
实际上我们不应该这么去编写测试,原因有三:1,我们的测试方法的结果依赖了其它方法、类的内部工作原理(否则我们怎么知道y轴需要检测的是8);2,会导致编写多个测试方法,我们肯定要把东南西北各个方向相关的方法都写一遍;3,依赖的其它方法虽然经过测试,但是如果发生变化,我们需要找到调用这个方法的所有地方进行修改
这里我们可以巧妙利用已经存在的方位方法进行测试用例编写:
编写moveForward()方法,使其变绿
轮船前进的完成了,后退的功能非常相似,就不详细说明了
故事迭代3
轮船可以左转或右转
和故事迭代2有点类似,在之前辅助类Location中包含了左右转的方法,我们可以结合实现
故事迭代4
轮船接收一个指令然后完成相应的动作(比如:lrfb表示左转右转前进再后退)
每个命令都用一个字符表示:f表示前进、b表示后退、l表示左转、r表示右转
先编写一个测试用例,接收一个字符串,解析并调用相关的方法
完成
红
的步骤后进入
绿
测试下结果没问题
故事迭代5
轮船行驶的地球是圆的,所以可以从一边的尽头跨越到另外一边
目前为止,轮船的构造函数只有一个参数location,代表轮船的方位,现在需要引入一个planet参数代表行驶的范围(水域大小)
新增一个两个参数的Ship构造函数,使其变绿
我们发现其实之前有过ship单个参数的测试方法,而且还有一个初始化方位的方法,其实我们可以将其重构成每次测试前都初始化一艘带方位和行驶范围的轮船
刚才的测试方法就可以简化为
Ship的构造参数也只需要保留一个就可以了
接下来编写一个往东边再前进回到x轴坐标1的测试方法,因为我们初始化的时候船就是朝东的,所以不同重新设置方向了
跑下测试用例肯定报错的,我们期望的是1,但是实际是51,超出边界了
度假中的同事之前已经在location辅助类中完成了跨越边界的逻辑,所以我们只要重构下ship中的前后形式方法,带上边界范围即可
运行下ship的所有测试方法,全部绿灯,故事迭代完成
故事迭代6
每次移动需要进行障碍检测,遇到障碍的话停在原处报告遇到的障碍
地球上的水域不是畅通无阻的,有暗礁和陆地,所以我们得在行驶区域中加入障碍物,轮船行驶的时候先检查是否有有障碍物
我们首先在初始化的时候在行驶区域内加入障碍物
重构下初始化的方法
无需添加实现,测试就可以通过
接下来我们测试有障碍物的时候,轮船无法行驶,我们的设计是让接收指令的方法返回一个字符串,代表每条指令的执行情况
根据测试代码,障碍物和船形式的路线如下:(先往蓝色箭头指示方向,后往绿色箭头指示方向)
执行下肯定是报错的,因为我们之前逻辑不支持障碍物,接下来要重构下我们的业务代码:
第一个地方:调用位置帮助类的时候,前进后退的方法要加上障碍物信息
第二个地方:指令接收方法要判断每次执行的结果,拼接成字符串返回
运行下我们的测试类
至此我们的遥控轮船开发完成,同事度假回来了,后面的需求交给他吧,毕竟我们也成为了TDD的践行者,让他放心的迭代吧!
版权归原作者 菡萏如佳人 所有, 如有侵权,请联系我们删除。