TDD也是一个知易行难的实践方法,需要反复进行练习与体会,下面列出了实践TDD的基本原则:
-
除⾮为了使一个失败的单元测试通过,否则不允许编写任何业务代码
-
在一个单元测试中只允许编写刚好能够导致失败的内容(编译错误也算失败)
-
只允许编写刚好能够使一个失败的单元测试通过的产品代码
要完全掌握TDD需要不断的练习和体会,实践TDD的第一步就是写一个失败的测试,对一些人来说这是个很难的步骤,好多人在给现成的代码加测试时候还痛苦异常呢,先写测试代码对他来说的难度可想而知,这个时候除了坚持别无选择,如果你是个对自己有更高要求和期望的人的话。
下面列出了写一个失败的测试过程中大家经常会遇到的一些问题:
从哪些测试开始,输入是什么?
其实无论是不是TDD,我们要写的代码的输入都是需求,所以第一步是充分沟通、理解需求,同时构思实现方案。需求沟通与细节澄清后完成初步设计,确定实现思路,即初步确定先做什么后做什么,然后据此对需求进行进一步拆分,形成待办列表,这部分的输出就是后续编写单元测试的输入。
这是整个过程的关键也是很多人初学时候最容易忽略的一步。在初步设计时需要注意:
- TDD也需要全局思考,通过对要解决的问题进行分析,确定实现策略后才是TDD过程,TDD的小步快跑并不是盲目的,需要在有一个大方向的前提下来进行。
- 注意坚持简单的原则,够用就好,避免过度设计,好的架构是在大方向正确的前提下演进出来的,不是一步到位的,开始时候想太多反而会影响实现思路和实现效率。
在拆分需求和分解待办列表时需要注意:
- 实现思路决定了后面的问题分解思路,如果还处于摸不到头绪的状态要先想清楚再继续,实现思路确定后再进行问题的拆分效果会更好。
- 拆分过程主要通过分析问题边界、输入和输出过程,按照“输入-过程-输出”的思路逐一进行拆分,最终得到待办列表。
- 对于待办列表需要注意列表描述要明确,因为这个是最终指导我们写测试的输入,所以需要包括具体的输入和预期输出情况。
- 随着对需求理解和实现思路的进一步深入理解,这个列表也是一个动态更新的过程,需要不断把新的待办添加进来,把失效待办移除。这一步可以通过在源码文件里通过TODO标签来记录。
如何控制测试用例粒度?
测试用例粒度控制实际是个十分主观的东西,按复杂程度判断还是按代码量判断呢,似乎都有道理,一般这时候只需要注意尽量确保一个测试方法只关注一个测试点就可以了。个人建议每个人根据自己所从事项目的情况灵活给自己制定适合自己的标准,测试驱动的目的是小步快跑,用适合你的步幅来执行就可以了。
初学者未找到感觉之前可以对自己要求严格一些,比如通过代码量判断粒度是否合适,如果你是使用IDEA的可以考虑安装一个LimitWIP插件,建议单组代码不超过80行。
如何判断测试量是否足够了?
理想情况下的TDD覆盖率应该是100%的,因为我们的业务代码都是由测试驱动而产生的。对于开始练习时候的各种练习题我们需要坚持这种标准。但是实际项目中我们大可不必过于教条,毕竟我们的目的是通过测试先行确保开发质量和开发效率,一般判断你的测试是否足够的唯一标准是你是否已经对你开发的代码具有足够信心,如果你觉得有足够信心的时候也就是测试代码足够的时候。
如何确保测试的可读性和可维护性?
为了提高工作效率,测试代码多数情况下不会像生产代码一样整洁。而当软件发生改变时,测试代码也必须随着改变,这种代码也会越积越多,最终会导致测试代码很难维护。所以我们在写测试代码时候也需要坚持一些原则:
- 适当的粒度,尽量一个方法只判断一种情况,避免一个方法中出现过多的断言,这样不管是以后阅读还是维护都会清晰很多,试想改一个不到10行的函数和改一个100行的函数哪个让你更有信心。
- 测试方法名称命名规范,可以采用Given/When/Then的格式命名,确保通过方法名就能基本理解测试目的。
- 对复杂场景增加注释信息。
TDD的第一步是很多人接触TDD的第一个难点,好多人直接找个理由然后就选择了放弃,我们应该认识到任何工具、流程和方法都需要一个持续学习的过程,没有不经过学习就带来立竿见影效果的方法,一旦决定了要学就请坚持直到掌握吧。
网友评论