关于 TDD

有一种编程思想叫测试驱动开发,英文全称Test-Driven Development,也就是 TDD。在这个过程中,最重要的就是编写测试代码,而且不是写完了业务逻辑之后才去写,是先写测试,然后根据需求,一步步的完善测试用例,最终写出有效的业务逻辑代码。

主讲师熊节老师提供了两个准则:

  1. 没有失败的测试就不许写代码;
  2. 只许写恰好让测试通过的代码;

开课后的第一个作业是 FizzBuzz。题目很简单,从 1 到 100,能被 3 整除的数打印 Fizz,能被 5 整除的数打印 Buzz,同时满足这两个条件的打印 FizzBuzz,其余的数字直接输出。题目不难,拿到题目,第一反应是有一个类 FizzBuzz 其中有 print 这个方法,然后在方法内部进行逻辑判断并打印,最后运行代码。

可是,老师不是这么做的,他的做法是:

  1. 编写测试用例 should_print_raw_value_by_1

    这个测试方法中,只是去检查 FizzBuzz 类的 print 是否与之相同,但并没有在 print 函数中进行任何的逻辑判断,只是输出了 null。第一次运行,测试不通过。

  2. 完善 FizzBuzz 类中的 print 方法,直接返回当前值;

    不做过多的任务,仅仅输出了 1 这个字符串。第二次运行,测试通过,

  3. 编写测试用例 should_print_fizz_by_3

    与第一步相同,未在 print 方法中增加对当前数字是否满足整除 3 的条件。第三次运行,测试不通过。

  4. 完善 print 方法中能否被 3 整除的判断。

    第四次运行,测试通过。

以此继续向前,不断进行尝试,直至把 print 方法完全编写出来。

我开始不理解,这么做不是麻烦了许多吗?甚至看起来有些傻,明知道那样运行测试是不可能通过的,为什么还去做这种事情呢?后来自己上手的时候才发现,这种方法是在锻炼程序员的思考能力以及对需求的理解。

当一个程序员做编写测试用例的时候,就相当于在给自己提需求。把客户(PM、甲方等)提出的问题用自己的思维方式进行思考。

第一步该怎么做?具体的代码怎么写,写完后,进行确认,确保在实现下一个需求时不把当前的 bug 带过去。这里的确认,就是通过编写测试代码进行的。不同的是,先写测试,根据测试结果(自己期望的结果,也就是自己给自己定的需求),来编写业务代码,让业务代码恰好得出自己所期望的目标。

这种测试先行的编程思想在需求不是那么清晰的时候,更能体现出其作用。

优点:

  1. 根据需求编写测试用例,对功能的过程及接口都进行了设计,而且这种从使用者角度对代码进行设计通常更符合后期的开发需求。
  2. 处于易测试的目的,促使开发者实现低耦合的设计,更多的依赖接口而非具体的类,提高系统的可扩展性;
  3. 将测试提到编码之前,并频繁的运行所有测试,可以尽可能避免和早发现错误,极大的降低了后续测试及修复的成本,提高了代码的质量,在测试的保护下,得以不断重构,以消除重复代码,优化设计结构,提高代码复用性,进而提高软件质量。

优点来源于 百度百科

封面图:Photo by eberhard grossgasteiger on Unsplash