引子

回顾

虽然我很早以前就听说单元测试,也曾经多次在项目中引入单元测试框架和单元测试的实践为代码质量的提升带来了一丝助力。

但这种方式更多的是从软件调试的角度出发,即将单元测试作为一种测试方法可用性的入口,而非从TDD、极限编程、或从"Fail Fast,Fix Fast”这种获得快速反馈的方式来使用单元测试,使得实际过程中单元测试的效果并不明显。

直到去年8月下旬开始参加极客学院的TDD实战课才进一步深入了解基于TDD的单元测试的流程、方法和实践的全过程,当时也间歇性的练习了一点Args等Kata项目,才逐步体会到TDD的妙处。

虽然到目前为止对于TDD的了解依然很浅,但在开发过程中,总是有意无意的“站在调用者的角度思考业务逻辑”,并尽可能的思考如何“编写可测试的代码”,总归是一种进步。

我的教训

总结自己学习TDD的一些经验教训:

  1. 需求的识别,总是按惯性一次性把整个需求全部提取了。
  2. 总是习惯于拿着代码一把梭,没有按照“Arange,Assert,Art”的步骤来规划任务。
  3. 步子迈得太大,方法拆得不够细,过程式代码的味道很浓,例如,在练习String Calculate过程中,就有非常明显的问题。当然,这也是许多初学TDD开发者的通病。

  1. 没有深刻理解“重构”的意义,只是把通过单元测试当做一个目的。
  2. Kata的练习频率依然不高,一周只有两到三次,每次不到一个小时。
  3. 单元测试和方法的命名不太规范,无法让人产生直接的理解。
  4. 方法的代码行较多,不符合优质代码的标准。
  5. 方法间适当的空行(分段)很重要。

什么是TDD

定义

TDD的全称是“测试驱动开发”,也是一种旨在提升代码质量的开发实践。这种开发实践的主要步骤是在编写产品代码之前,先编写单元测试代码,然后再由测试代码来决定写什么产品代码,其目的是取得快速反馈,并使用“illustrate the main line”方法来构建程序。

测试驱动开发是戴两顶帽子思考的开发方式:先戴上实现功能的帽子,在测试的辅助下,快速实现其功能;再戴上重构的帽子,在测试的保护下,通过去除冗余的代码,提高代码质量。测试驱动着整个开发过程:首先,驱动代码的设计和功能的实现;其后,驱动代码的再设计和重构。

原则

在上述经验教训过程中,有些步骤其实与TDD的三原则相违背,让我们来回顾一下这三个原则:

  • 不允许编写任何产品代码,除非允许失败的测试通过。
  • 不允许编写多余一个的失败测试,编译成功也是失败。
  • 不允许编写多于恰好让测试通过的产品代码。

步骤

TDD其实也有一系列完整的操作流程,包括如下五个步骤:

  • 添加一个小的测试
  • 运行所有测试并且失败
  • 做一点修改
  • 运行所有测试并且成功
  • 重构以消除重复

图1(红绿重构)

可行性之争

TDD也是一种充满争议的开发实践,许多人都吐槽,这种方式在原本开发代码之余,还得额外花三分之一的时间来编写测试代码。不过,我还是推荐《代码整洁之道-程序员的自我修养》这本书中,Robert Bob大叔在第5.1小节说的几句话:

1、此事已有定论!

2、争论已经结束!

3、GOTO是有害的!

4、TDD确实可行。

他明确指出:

过去人们对TDD充满争议,就此发表了不少博客和文章,如今争议依旧来袭。所不同的是,以前人们是认真尝试着去批判和理解TDD,而现在只有夸夸奇谈而已。结论很清楚,TDD的确切实可行,而且每个开发人员都要适应和掌握TDD。

TCR

在《极限中国社区》曾经介绍了一种测试驱动开发过程中的实践模式,这种实践被称为“TCR”。

在实践过程中,开发者始终保持着测试,成功则提交,失败则回滚到上次的代码这样的循环。在并使用了插件来进行自动化回滚,确保每个方法的开发时间被控制在非常小的时间粒度上。这样保证了开发者能够以非常小的步子,非常快的频率,实现代码的开发过程。

TCR

Kata

优秀的代码从来不是天生的,而是通过后天不断的练习培养出来的,尤其是要想写出符合面向对象设计的的好代码,更是需要“刻意练习”。

Kata被人称为是唯一的一种练习TDD的形式。

“Kata”是一种来自日语词汇“形式”的翻译,它描述了武术练习中,通过一种精心编排的动作模式,用来训练自己达到肌肉记忆的水平。

Kata的练习例子是如此之多,只要你有心,总是能在海量的示例代码中找到最适合自己的一个例子。

例如,我所使用的Roy Osherove设计的例子“String Calculate”就是一个非常不错的示例。(当然,我给出的是一段反例代码。)

1、An empty string returns zero
2、A single number returns the value
3、Two numbers, comma delimited, returns the sum
4、Two numbers, newline delimited, returns the sum
5、Three numbers, delimited either way, returns the sum
6、Negative numbers throw an exception
7、Numbers greater than 1000 are ignored
8、A single char delimiter can be defined on the first line (e.g. //# for a ‘#’ as the delimiter)
9、A multi char delimiter can be defined on the first line (e.g. //[###] for ‘###’ as the delimiter)
10、Many single or multi-char delimiters can be defined (each wrapped in square brackets)

当然,FizzBuzzThe Prime Factors Kata,Args也是一个非常不错的示例。重要的并非例子本身,而是通过持续不断的练习,形成自己的肌肉记忆。

引文中,作者Peter Provost认为,最好的办法:

我对人们的建议是连续两周每天早上做一个30分钟的练习。然后再选一个,每天做一次,坚持两周

我不建议大家在工作中练习Kata,除非他们已经准备好了。你应该通过练习一周或六次,直到你已经决定对TDD的循环非常适应为止。否则,就像参加了一场没有技术水平的比赛。

什么是TDD(一)的更多相关文章

  1. TDD在Unity3D游戏项目开发中的实践

    0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...

  2. 初步认识TDD

    TDD,测试驱动开发(Test Driven Development)是极限编程中倡导的程序开发方法,以其倡导先写测试程序,然后编码实现其功能得名.本文将对TDD有一个较为系统的认识.    基础属性 ...

  3. Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记

    0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...

  4. TDD原则

    TDD 介绍 测试驱动开发,或者叫 TDD,是一个敏捷方法,通过确保在代码是先前手动编写测试用 例,用测试来驱动开发,从而翻转开发生命周期(它不只是作为一种校验工具). TDD 的原则很简单的: 只有 ...

  5. Atitit各种SDM 软件开发过程SDP sdm的ddd tdd bdd设计

    Atitit各种SDM 软件开发过程SDP sdm的ddd tdd bdd设计 1.1. software development methodology (also known as SDM 1 1 ...

  6. 使用IdleTest进行TDD单元测试驱动开发演练(3) 之 ASP.NET MVC

    一.[前言] (1)本文将用到IOC框架Unity,可参照<Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备>(2)本文的解决方案是基于前述<使用I ...

  7. 使用IdleTest进行TDD单元测试驱动开发演练(2)

    [前言] 1. 有关上篇请参见<使用IdleTest进行TDD单元测试驱动开发演练(1)>,有关本篇用到Entity Framework Code First请参见<使用NuGet助 ...

  8. 使用IdleTest进行TDD单元测试驱动开发演练(1)

    [前言] 开发工具:Visual Studio 2012 测试库:Visual Studio 2012自带的MSTest DI框架:Unity 数据持久层:Entity Framework 前端UI: ...

  9. 前端自动化测试 —— TDD环境配置(React+TypeScript)

    欢迎讨论与指导:) 前言 TDD -- Test-Drive Development是测试驱动开发的意思,是敏捷开发中的一项核心实践和技术,也是一种测试方法论.TDD的原理是在开发功能代码之前,先编写 ...

  10. TDD学习笔记【四】--- 如何隔离相依性 - 基本的可测试性

    前言 相信许多读者都听过「可测试性」,甚至被它搞的要死要活的,还觉得根本是莫名其妙,徒劳无功.今天这篇文章,主要要讲的是对象的相依性,以及对象之间直接相依,会带来什么问题.为了避免发生因相依性而导致设 ...

随机推荐

  1. C# 防XSS攻击 示例

    思路: 对程序代码进行过滤非法的关键字 新建控制台程序,编写代码测试过滤效果 class Program { static void Main(string[] args) { //GetStrReg ...

  2. 机器学习-决策树系列-XGBoost算法-chentianqi大神-集成学习-31

    目录

  3. MySQL 及调优

    存储引擎的种类 MySQL 中存在多种存储引擎,比如: InnoDB 支持事务: 支持外键: 同时支持行锁和表锁. 适用场景:经常更新的表,存在并发读写或者有事务处理的业务场景. MyISAM 支持表 ...

  4. 如何让golang的web服务热重载

    有很多方法可以热重载 golang Web 应用程序或 golang 程序. 我选择gin(不是web gin框架)来进行热重载. 首先在 GOPATH/bin下安装gin,命令如下所示: go ge ...

  5. [粘贴]Introducing Exadata X9M: Dramatically Faster, More Cost Effective, and Easier to Use

    https://blogs.oracle.com/exadata/post/exadata-x9m   The Exadata Product Management and Development t ...

  6. [转帖]Navicat连接openGauss数据库报错

    news/2023/10/19 21:23:19 错误信息:fe_sendauth:invalid authentication request from server:AUTH_REQ_SASL_C ...

  7. [转帖]使用 EXISTS 代替 IN 和 inner join

      在使用Exists时,如果能正确使用,有时会提高查询速度: 1,使用Exists代替inner join 2,使用Exists代替 in 1,使用Exists代替inner join例子: 在一般 ...

  8. Chrome浏览器不同版本兼容性的验证方法

    Chrome浏览器不同版本兼容性的验证方法 背景 上周客户现场有出现使用国产信创设备上面的奇安信浏览器出现兼容性的问题. 开发认为是测试不全面导致. 认为测试应该必须测试过特定浏览器才可以进行说明. ...

  9. [转帖]Java 内存管理

    https://www.cnblogs.com/xiaojiesir/p/15590092.html   Java 内存模型简称 JMM,全名 Java Memory Model .Java 内存模型 ...

  10. CentOS8 安装Oracle19c RPM的办法

    1. 下载相应的rpm包 我这边使用的主要有: -rw-r--r-- 1 root root 19112 Apr 5 15:13 compat-libcap1-1.10-7.el7.x86_64.rp ...