TDD 测试驱动开发与精益

2000年的时候,开始学软件工程,听到极限编程 (eXtreme Programming) 里面强调要测试驱动开发TDD (Test Driven Development)。

后面在做培训时,对开发人员也说要先写测试用例,再写代码。

第一次开始对TDD有印象,是看 Robert MARTIN (敏捷宣言者大师之一)的经典 - 用TDD编写保龄球计分程序,现在国内很多网站都有这案例的中文翻译。

有些开发人员都问:“为什么要这么做?写完程序以后,然后再写测试用例,不是更正常?”

三年前开始讲PMI的ACP敏捷专业课,讲到敏捷其中一个很核心的概念就是精益。最近一次事件让我体验到:为什么我们要测试驱动开发? TDD 与精益的概念如何配合?

我有一位几十年老同学,大学读的电机工程,他一直很有兴趣研究Linux,这几年开始玩树莓派,也非常精通。

最近我找他,希望用手上的树莓派安装 Ipython, Jupyter Notebook 等开源应用软件。李先生一直的信念就是用最简单、最轻易的方法解决客户手上的问题,不浪费资源。例如我三年前开始试用尝试建立wiki服务器给客户用的时候,他就建议我用树莓派来建。

他说:”树莓派不仅省电而且快,也不知道你这个概念是否持久,我不会浪费时间,到一个大型服务器上去安装 Linux + Mediawiki ,如果你觉得这可以, 便继续用吧。如果觉得它性能不够,我下一步才帮你换更大型的服务器。”

到现在我已经有20多个客户,一直还是继续用树莓派来协助评估,证明他的思路不错。

回到我刚才说要安装 Jupyter Notebook ,他安装好那个程序包后,一直没动。我问他什么原因?他说:”很简单,我不熟识软件工程,也不懂如何测试。 肯定要找你测试一下,我才知道有没有做错?看是否需要返工。”

所以我们就约好周日我回到到办公室跟他远程测试。

打开树莓派,我就用VNC 远程进入他的树莓派,打一些最基本的 Ipython 指令,验证没问题。

然后下一步我要跑一些比较复杂,要使用 Pandas 包的python程序,发现还没有安装。他马上到网上去找安装程序和网上对树莓派如何安装 PANDAS 的方法。 处理好后,我再跑对应的程序,都跑通了,包括之前跑过的指令。前后两个小时,按本来计划,测试成功。

我回想一下,其实他的思路就是精益。在有限的资源,以最低投入,达到客户要求,不多做。李先生他每做完一步,如果没有通过测试,不会浪费时间走下一步,这也是精益和测试驱动开发的原理。

从这经历,我体会到为什么我们在写程序时,必须预先想想怎么测试?

2「Web程序的TDD」


如果你是希望在网站开发用TDD,也可参考 Percival "TDD with Python",他以Selenium做WEB功能测试,配合python 做单元测试,加上 Django 的引擎,很详细地从如何先写功能测试,从客户角度来测试不通过,然后再深入以代码语句思路写单元测试,不通过,再针对单元测试写程序,逐步完成,最后通过功能测试。

原则是按部就班地开发,每一步都有单元测试来验证,避免写了一大堆复杂程序,无法验证。

程序员会问为什么我们要这么小的部分都做单元测试?

答:

1、轻松的单元测试容易写,比较简单,不会花费很多时间

2、因为任何程序都会按时间变化,越来越复杂,有了单元测试,后面的测试就有依据,知道改动是否出错,没有的话,就没信心去改程序,不知道是否没问题。

(和我们工程的概念一样,把工程细分,每个子系统都要确保质量达标,尽量找出缺陷,才进行下一步。)

3「争议」

网上也很多关于是否TDD的争论,成为两派:

* 一派是坚持要先写测试用例,再写编码

* 另一派觉得TDD太多余,如果功能测试做得全,不一定要有单元测试

这个争论让我想起这段时间教ACP敏捷管理的一个分享原则,叫——守 破 离

4「守 破 离」

英文翻译成 “Shu – Ha – Ri ” 意思是学习合气道,要先从基本功出发 (守),按规则一步一步做

当你理解以后,就能融会贯通 (破),融合管理到一定境界就是大师级了 (离)。

像宫本武藏(江户时代著名剑术家)一样,一生赢了六十多决斗,然而到了晚年,他在《五轮书》总结,不要局限于某种刀法,最重要是抓住原理。

敏捷大师 Mr Cockburn 有一次到企业做 Class-responsibility-collaboration (CRC) card 咨询培训,因为他很熟悉 CRC 方法,他觉得只要有助于面向对象(OO) 设计,不一定要按原本的方式,可以简化。但学生都不熟悉,一直在问“请你告诉我们从头到尾,每一步如何做,我们照着做”大师没办法,最终按最原始一步步如何做来教,学生才能懂,是 守 破 离的守。

TDD测试驱动开发也一样,把TDD看成“守”,当没概念还是要从最基本的概念入手,我们每个程序都应该有测试,所以自然的顺序是先写测试用例,再写代码,也更好帮你理解程序的功能。

所以TDD就是做好程序基本功的基础,当你已经掌握这基础,也可以灵活处理,可能不一定要每个次先写测试用例,但底线是每个代码都要有单元测试。

但是有些人觉得,只要有功能测试,单元测试可以不做。

你赞同吗?

功能测试是黑盒测试,从客户的角度测试总体功能,无法真正判断代码是否正确,反过来,单元测试是白盒测试,从代码的功能角度,验证代码是否正确,所以功能测试是不能替代单元测试。尤其的当代码有功能上变化时,更需要有单元测试来验证这些改动是否有误,所以单元测试的复用率非常高。

大家越来越多使用自动集成工具,如果有单元测试,每天自动集成就不仅仅看编译是否通过,也须要通过单元测试,更好保证代码质量,是很有效率的回归测试。

5「国内案例」

上周在杭州跟一位很资深的开发主管对话,他回国前在日本工作了接近10年,他说很佩服日本注重开发质量,例如很注重单元测试,所以回国后在团队严格要求要有单元测试。

我问:现在有很多静态代码检测,为何还要单元测试。

他答:目的不同,静态代码检测只能从过去的历史查常见的语句、命名问题,如果是设计本身逻辑问题就无法查出。 从他多年的经验,必须有单元测试才有信心这个程序是正常,但单靠查看程序是无法达到。所以他严格要求团队,代码经过检验后(自动静态检验或代码走查),还必须做单元测试才能进入下一步的集成、系统测试。

他也说,单是靠集成测试、功能测试是无法确保程序每一部分都正常。

他还说TDD 有三点好处:

1、让开发人员在编码前去理解设计和需求

2、让开发人员知道代码可验证性的重要

3、强迫开发人员主动与设计和需求人员沟通,否则无法设计出单元测试用例

但TDD对团队成员素质要求较高

从以上他对TDD的解读,我我可理解他为什么如此坚持单元测试。

6「质量原则」

质量基本原则:每人必须保证产出物的质量,保证交给下游(客户)东西的质量,不要依赖你的客户代你找出缺陷。目标是减少返工。

7「研发管理者对这TDD分享的反馈」

意见可以分成两大类, 如果公司规模较小(如200人以下):

* 有些经理觉得如项目超过100人月 - 必须用TDD,少于50人月则不必。

* 另一些觉得实施会漫漫长路

但规模大,产品化的公司:

* 例如,一位5000人规模公司的研发总监表示:

“测试驱动的确是比较好的实践,随着微服务和前后台分离开发,面向接口(服务)编程也是主流。现在很多都在提接口测试,我觉得这个可能更容易实现。其实就是先从PUBLIC的方法入手。

要全部方法都单元测试,工作量上还是有很大的阻力!如果是全栈工程师,让他写单元测试是很难。”

从以上反馈,我发现TDD跟项目或客户对质量的重视度有关系; 例如以上那5000人规模公司,管理层一直很注重软件质量,它们2018年投入很多精力,加强静态代码检验,来提高质量。

如果公司希望提高代码质量,做好单元测试,便应先从白盒测试 培训开始。

8「后记」

我也把这分享发给李先生,他说: “我不懂什么精益 、TDD、 软件开发,但我的经验告诉我,用最简单、最省事的方法,要客户确认,避免浪费。客户的需求也会变,这样才能保证做出的东西是客户要的。”

Reference:

Percival, Test Driven Development with Python 2/e

Martin R.C., Agile software development - principles, patterns, and practices

源文出自高等级主任评估师:宋世杰

点击关闭
  • CMMI认证客服

    CMMI3认证客服

    CMMI咨询

    CMMI4认证