体验测试驱动开发
单元测试不仅改变了我们测试生产代码的方式,它也想尝试改变开发者的编程模式,假设我们先编写测试用例,再编写生产代码,这种激进的模式,不知道大家想过(或用过)没有?有同学会说,连生产代码都没有,单测测什么?这不是天方夜谭吗?事实上,这不是痴人说梦,JUnit的作者,就提出了设计驱动开发(TDD),并认为它能极大的提升软件质量和开发效率。

无限地逼近极限
测试驱动开发,从编写测试开始,到最终测试全部通过,功能自然而然的实现完全,这种魔幻般的开发方式如下图所示:

如上图所示,先从测试新增开始,然后再运行单测,这时,测试妥妥的无法通过。遇到不能通过的单测时,开始写实现逻辑,然后不断的完善测试和生产代码,直到该测试通过。为了让测试通过可能会在生产代码中采用一些比较粗暴的写法,此时就需要重构代码,优化结构,随后再次运行测试,通过后,就开始下一个循环。
随着这种看似极限的循环不断运行,生产代码一点点的被构建出来,同时配套的单元测试也被编写出来,代码质量自然不低。TDD的采用难度是不小的,但先写测试的目的是要开发者明白自己要干什么,聚焦到实现层面要做点什么,因为很多开发者在编程时,往往不知道自己在做什么。聚焦到一个单点问题,然后快速循环,才能专注且高效的解决问题,实现功能。
可取之处
TDD过于的极限,尤其是生产代码还没有的情况下就开始写单测,让人难以接受。生产代码写完了,再写单测,就像补作业,太晚了,也不好。那么取其中间,先定义好接口和主要方法,不做实现,然后开始写单测,这样单测就和生产代码一起长出来了。
虽然TDD不是强制要求,但是透过它还是能看到不少可取之处的,它能够让代码上生产环境之前,以使用者的角度审视编写的代码,至少可以做到以下三点:
(1)如果代码难测,那就是对问题的分析还没有到位;
(2)如果存在大量的Mock,那就是依赖过于复杂或职责不清;
(3)能够通过反向刺激让我们看到代码的不足。
其中第三点的反向刺激包括:这个方法命名是否够妥帖?别人用这个函数会误用吗?这个类是不是承担了过多的职责?好的测试从来都不是在制造麻烦,而是让你有机会更早的发现问题,并且以极低的代价修复问题。