程序员真的有必要掌握 TDD 吗?

你好,我是猿java。

你听过或者了解过 TDD 吗? 你知道 TDD 是什么吗?你知道它是如何工作的吗?今天我们就来聊聊 TDD。

曾经在Martin Fowler(马丁·福勒) 的个人博客里看过一篇关于Kent Beck、David 、Martin Fowler 3位大牛关于 Is TDD Dead 的讨论以及David
TDD is dead. Long live testing. 的帖子。

几位作者的部分介绍

1
2
3
4
5
6
7
8
9
10
Martin Fowler(马丁·福勒),出生于英格兰,后移居美国,像微服务,

DSL(领域设计语),统一建模语言等思想都是出自他,大家有兴趣可以看看他的个人博客:

https://martinfowler.com/,上面有很多优秀的博文,思想值得我们拜读。

Kent Beck:美国人,JUnit单元测试框架作者之一,敏捷开发的开创者之一

David Heinemeier Hansson:丹麦人,Ruby语言创始人

TDD 是什么 ?

TDD 是来自极限编程,百度百科的解释如下:
TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前, 先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD虽是敏捷方法
的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他 开发方法和过程。

这个解释是比较片面的,其实TDD 包含两大部分:ATDD 和 UTDD

ATDD

Acceptance Test Driven Development,验收驱动开发。比如,QA(质量保障)会编写测试用例,然后和PM(产品经理),RD(技术开发)一起评审,这个过程可以帮助RD更好的理解业务需求和验收条件,以至于在后面的代码编写中带着验收目标直到验收测试用例通过。
测试的方式有很多,比如BDD(功能测试),白盒测试,集成测试等等,根据不同的场景采用不同的测试手段,以便达到验收通过。

UTDD

Unit Test Driven Development,单元测试驱动开发,RD先编写单元测试用例,然后再编写实现代码直到单元测试通过。
关于ATDD和UTDD 在Thoughtworks官网,有一张抽象图,大家可以参考下:

img.png

下面整理了一个xmind图

img.png

如何做好 TDD?

在分析TDD方案之前,我们先来解决一个问题:测试驱动开发,整个过程从哪里开始?

答案:测试

那么,测试又从哪里开始呢?
答案:需求。
如果没有需求,测试的目标是什么?因此需求是测试的源头;面对庞大的需求,要如何测试?方法是将需求分解成一个一个可实施测试的小任务。
所以 测试驱动开发要从任务分解开始。

下面摘取了 Thoughtworks 官网的2张图片,来表达TDD的整个过程。
TDD实施-步骤示意图:

img.png

TDD实施-协作示意图:

img.png

个人觉得TDD 可以和 DDD 一样,从战略和战术两个角度来实施。

战略角度

战略角度,更多是一个思想层面的方法论,它可以指导我们以一种更优的方式去实施TDD。

下面先描述一个需求从提出到上线的整个生命周期:

当接到一个新需求时,

  • 首先,PM会有需求评审,评审会阐述业务背景,讲解需求解决的问题以及要达到什么目标;
  • 然后,RD会根据需求评审,做业务分解、上下游沟通、接着做技术详设,技术串讲;
  • 接着,QA会结合需求评审和RD的技术串讲编写测试用例以及用例评审,多方拉齐验收目标和上线时间;
  • 再接着,RD会做架构设计,代码设计以及代码编写,代码测试;QA会做测试相关的工作,比如:用例设计,测试脚本等;
  • 最后,RD开发完成&提测,QA进行测试直到准出,PM进行最后的验收直到代码上线;

整个流程体现了TDD的战略思想,整个生命周期为ATDD和UTDD提供了一定的流程规范。

战术角度

战术角度,更多是从技术层面来阐述。在战略角度我们提出了方法论,针对流程里面的每个步骤要怎么落地,这个就是战术角度。

  • 比如:需求分解,需要按照什么维度分解,是按照领域划分还是按照过程划分,任务分解成多大才算合理。
  • 比如:架构设计,要用什么架构思想,是六边形架构还是洋葱架构。
  • 比如:代码设计,需要用到什么设计模式,适配器模式还是工厂模式。
  • 比如:代码编写,需要用到什么数据结构,算法,怎么让代码更具有复用性。
  • 比如:测试,如何设计测试用例,选用什么测试框架,怎么让测试变得自动化

TDD的实施有一个经典三步曲:红 - 绿 - 重构,不论是ATDD还是UTDD都可以按照这个三步来实施,三部曲示意图如下:

img.png

在很多测试框架中 红代表测试没有通过,绿代表测试通过,而要想让红变成绿就需要经过不断的重构。

因此,我们可以理解:为了写测试,首先“驱动”着我们理解业务,把需求分解成一个个的任务,然后会“驱动”着我们给出一个可测试的设计,而在具体的写代码阶段,又会“驱动”着我们不断改进写出来的代码。把这些内容结合起来看,我们真的是在用测试“驱动”着开发。

有了战略和战术的指导,最主要的就是需要修炼支撑这些策略的能力。实施 TDD 最好需要具备以下能力:

  • 测试前移(左移)的思维能力
  • 业务和技术需求的分析和任务拆分能力
  • 测试用例设计能力
  • 自动化测试开发
  • 能力代码重构
  • 能力持续改进的能力

误区

误区1

在很多程序员的理解中,UTDD就是TDD,TDD就是UTDD,以至于我们把面向业务或测试的ATDD给忽略了,因此,无形中把TDD的范围给缩小了。下面给了一个ATDD和UTDD的对标表

误区2

TDD 就是先写测试后写代码,原因已经在TDD 战术部分中分析过。

TDD真的”死了”吗?

如文章开头 Is TDD Dead?

答案是:NO, 而且目前TDD活的还是不错的,很多公司一直在践行它,只是没有特别去强调它是TDD的范畴。 同时,TDD不是银弹,不可能解决实际工作中的任何问题,我们要做的是不断的学习,比较和总结,根据实际的业务需求去实施,毕竟合适才是最好的。

程序员真的有必要掌握TDD吗?

很有必要,我们不一定要特别强调TDD这个概念,但是TDD根本就是保证程序员的代码质量,而代码质量是程序员的底线
UTDD可以帮助程序员更好,更系统的去写单测;ATDD,可以让程序员更好的了解业务,通过更深度的了解业务来保证代码对业务的健壮性。

参考文献

Thoughtworks官网TDD

Martin Fowler博客

书籍:Java测试驱动开发 (Viktor Farcic著,袁国忠译)

敏捷软件开发(RobertC.Martin 著)

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。

drawing