为什么那些人选择TDD这种方式开发?

你是否听到过TDD(Test Driven Development)这种开发方式?是否身边人坚持使用这种开发方式呢?你是否也体会到TDD所带来的那部分好处呢?


TDD

《在开发人员如何拥抱?》中,并没有提必须要用TDD的方式,不过TDD有其自身的好处,我自身也是TDD的实践者。

TDD指的是 Test Driven Development --- 测试驱动开发。通过测试代码来驱动出业务带的实现。是一九九几年哪个时间段通过实践总结出来的一种然间开发方式,TDD的目的:聚焦价值,让程序代码成为易于修改的代码。

我是一名TDD的实践者,对TDD也有一个自己学习和理解的过程。从刚开始不清楚为什么这么做,到后来一切围绕商业价值后实践TDD的摸索,逐渐体会了TDD这种实践方式的用意。

1. 为什么使用UT来驱动出业务代码?

TDD是通过单元测试来驱动业务代码的实现。所以我们先回顾下单元测试能够带给我什么?

  1. 单元测试是一种验证行为;
  2. 单元测试避免了相当数量的反馈循环,尤其是功能验证方面的反馈循环。
  3. 单元测试也是一种编写文档的行为;
  4. 单元测试更是一种设计行为;

1.1 单元测试是一种验证行为

单元测试是一种验证行为,这个或许是很多人脑子中对单元测试唯一的定位。因为通过单元测试确实能够在一定程度上验证实现代码在特定情况下是否按照期望来运行相关逻辑。

1.2 单元测试避免相当数量的反馈循环

而且单元测试避免相当数量的反馈循环,尤其是功能验证方面的反馈循环。在开发开发中我们发现很多开发者在验证自己开发出来的功能时,会采用下面两种方案:

  1. 不测,凭直觉写完业务逻辑,直接丢给测试人员。
  2. 测,但是得通过UI界面上的操作,或者网络请求工具,或者临时编写个main函数再注释掉的方式来验证自己实现的业务代码。

第一种方法肯定是不可取的,因为反馈循环的链条最长,需要等待测试人员测试,测试人员给出反馈时需要讲清楚上下文,并找到稳定复现的方法,并通过文字记录、语言表达等途径来表达给开发人员问题,开发人员还需要从当前做的事情的上下文中切换到出现问题的上下文中,对软件修修补补。在不考虑沟通效率的前提下,这个反馈循环是最长的,成本最高的。

第二种,虽然开发人员进行测试,测试的目标代码和其他环境的依赖太多了。比如只需要验证某一行代码,却要从网络请求开始。使用main函数确认临时测试了代码,但是也给代码带来了坏味道,注释的代码在后续并没有什么约束的作用,即使通过口口相传的方式建立了约束,那么想想这样的反馈高效吗?稳定吗?

通过单元测试来验证业务代码,其实是一个一劳永逸的行为。不但验证了当前的目标的代码,同时也留下了约束,来描述当前某段代码的正确行为是什么。

1.3 单元测试也是一种编写文档的行为

说单元测试是一种编写文档的行为,其实需要建立在一定的前提下,因为代码本身就不适合做阅读,在没有良好可读性代码的时候,那单元测试做文档更是一种痛苦。

什么情况下单元测试能够作为一个好的文档呢?

一定的约束和纪律性能给团队带来更高的效率。

UT文档化需要分两步

  1. UT和业务描述建立关系
  1. UT自身的描述

我们平时肯定会接触到Feature、UserStory、Task、Bug等,现在又加上UT,如何让UT来为我们带来文档的作用呢?可以通过索引来实现,我们按照下面的格式为UserStory,Feature建立索引:

F=Feature
S=User Story
T=Task

然后为其加上序号

F01 S01 T01
或者
F01 S01

这样每一个测试方法通过索引都能够和业务文档上Task或者User Story的描述建立关系。

UT自身的描述:指的是通过简单的规则约束来让UT更加易读易理解。BDD给我们提供了一种很好的描述方法:given、when、then。

Given:在什么亲体条件下
When:发生什么事情是
Then:结果是什么

为了使UT更加易读,我们让测试方法名和测试方法块都按照given、when、then的方式来组织。

下面是方法名的建议:

should...when...given...

下面是方法块的建议:

public void should_response_a_ticket_when_parking_car_given_parking_lot_with_3_space_and_a_car() {
    ParkingLot parkingLot = new ParkingLot(3);
    Car car = new Car();

    Ticket ticket = parkingLot.parking(car);

    assertThat(ticket).isNotNull();
}

上看的这个方法中,通过Given、When、Then的结构来代码结构,中间使用空行分隔。

下面是个实际的例子:


F01:作为一个普通用户,我通过快递柜,存快递和取快递。

S01:作为一个普通用户,我可以通过快递柜屏幕上的按钮,选择快递柜箱子的大小后,将快递物品放入到快递柜中。

AC01: 
  given:一个普通用户,一个有空位的快递柜;
  when:当点击存件按钮
  Then:屏幕显示打开的快对柜箱的位置,并打开该快递柜的门,

下面是对象的测试代码:

public void should_open_the_door_when_click_post_button_given_a_express_box_lot_with_3_space_and () {
    ...
}

public void should_not_open_the_door_when_click_post_button_given_a_express_box_lot_with_0_space_and () {
    ...
}

通过Test Case我们能够清楚到找到业务上下文,并通过 Test Case的方法名和方法体结构清晰的只要在测试什么内容。

1.4 单元测试是一种设计行为

单元测试是一种设计行为,这是单元测试让我始终受益匪浅的地方,因为测试先行的方式让我在实现业务代码的时候就是两件事:聚焦、让代码易测试。

后者较容易理解,因为易测试代表了在一定程度上代码已经实现了解耦。你可能会举出一些例子或者场景来反驳,其实想清楚要测试什么,哪些是这次测试不需要的但是又被迫加进来的,分清楚要测的和增加干扰的信息其实就意味着我们能够对代码进行再次的重构和解耦来让代码更加容易测试。

上面也体现了一部分聚焦,但是还有更多可以聚焦的内容。比如:

先写测试时需要先组织测试条件和验证条件,最后写实现。因为then的约束条件,我们每次只需要聚焦在一小块代码实现上,即使在代码实现上遇到了依赖的时候,我们可一直在依赖上返回期望的结果,并逐渐一个或多个test case方便我们管理好test case清单,并聚焦在当前实现上。

因为每次都是聚焦一小块业务代码的实现,对一小块代码进行添加、修改所以更容易划分清楚职责。

应对多出的细节设计,最终我们聚焦在代码级的设计上,让代码更加易读、提高。如果你能够识别出Bad smell,熟悉设计原则和设计模式,那么生成的代码更加易维护。

2. TDD时对代码的修改行为往往会重复下面的动作。

TDD大致流程

重复上面的代码非常重要,因为良好的代码往往不是一次生成的,而是通过不断重构生成的。

重复面的过程其实是在提前review修改点,将codereview的反馈环在此变短。如果是初次上手TDD,可以聚焦在Simple Design上,如果是TDD的老手,设计原则、设计模式会让TDD事半功倍。

关于如何《从Simple Design入手让代码易修改》,可以看看这篇文章。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容