什么是TDD(一)
引子
回顾
虽然我很早以前就听说单元测试,也曾经多次在项目中引入单元测试框架和单元测试的实践为代码质量的提升带来了一丝助力。
但这种方式更多的是从软件调试的角度出发,即将单元测试作为一种测试方法可用性的入口,而非从TDD、极限编程、或从"Fail Fast,Fix Fast”这种获得快速反馈的方式来使用单元测试,使得实际过程中单元测试的效果并不明显。
直到去年8月下旬开始参加极客学院的TDD实战课才进一步深入了解基于TDD的单元测试的流程、方法和实践的全过程,当时也间歇性的练习了一点Args等Kata项目,才逐步体会到TDD的妙处。
虽然到目前为止对于TDD的了解依然很浅,但在开发过程中,总是有意无意的“站在调用者的角度思考业务逻辑”,并尽可能的思考如何“编写可测试的代码”,总归是一种进步。
我的教训
总结自己学习TDD的一些经验教训:
- 需求的识别,总是按惯性一次性把整个需求全部提取了。
- 总是习惯于拿着代码一把梭,没有按照“Arange,Assert,Art”的步骤来规划任务。
- 步子迈得太大,方法拆得不够细,过程式代码的味道很浓,例如,在练习String Calculate过程中,就有非常明显的问题。当然,这也是许多初学TDD开发者的通病。
![]()
![]()
- 没有深刻理解“重构”的意义,只是把通过单元测试当做一个目的。
- Kata的练习频率依然不高,一周只有两到三次,每次不到一个小时。
- 单元测试和方法的命名不太规范,无法让人产生直接的理解。
- 方法的代码行较多,不符合优质代码的标准。
- 方法间适当的空行(分段)很重要。
什么是TDD
定义
TDD的全称是“测试驱动开发”,也是一种旨在提升代码质量的开发实践。这种开发实践的主要步骤是在编写产品代码之前,先编写单元测试代码,然后再由测试代码来决定写什么产品代码,其目的是取得快速反馈,并使用“illustrate the main line”方法来构建程序。
测试驱动开发是戴两顶帽子思考的开发方式:先戴上实现功能的帽子,在测试的辅助下,快速实现其功能;再戴上重构的帽子,在测试的保护下,通过去除冗余的代码,提高代码质量。测试驱动着整个开发过程:首先,驱动代码的设计和功能的实现;其后,驱动代码的再设计和重构。
原则
在上述经验教训过程中,有些步骤其实与TDD的三原则相违背,让我们来回顾一下这三个原则:
- 不允许编写任何产品代码,除非允许失败的测试通过。
- 不允许编写多余一个的失败测试,编译成功也是失败。
- 不允许编写多于恰好让测试通过的产品代码。
步骤
TDD其实也有一系列完整的操作流程,包括如下五个步骤:
- 添加一个小的测试
- 运行所有测试并且失败
- 做一点修改
- 运行所有测试并且成功
- 重构以消除重复
![]()
可行性之争
TDD也是一种充满争议的开发实践,许多人都吐槽,这种方式在原本开发代码之余,还得额外花三分之一的时间来编写测试代码。不过,我还是推荐《代码整洁之道-程序员的自我修养》这本书中,Robert Bob大叔在第5.1小节说的几句话:
1、此事已有定论!
2、争论已经结束!
3、GOTO是有害的!
4、TDD确实可行。
他明确指出:
过去人们对TDD充满争议,就此发表了不少博客和文章,如今争议依旧来袭。所不同的是,以前人们是认真尝试着去批判和理解TDD,而现在只有夸夸奇谈而已。结论很清楚,TDD的确切实可行,而且每个开发人员都要适应和掌握TDD。
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)
当然,FizzBuzz或The Prime Factors Kata,Args也是一个非常不错的示例。重要的并非例子本身,而是通过持续不断的练习,形成自己的肌肉记忆。
在引文中,作者Peter Provost认为,最好的办法:
我对人们的建议是连续两周每天早上做一个30分钟的练习。然后再选一个,每天做一次,坚持两周
我不建议大家在工作中练习Kata,除非他们已经准备好了。你应该通过练习一周或六次,直到你已经决定对TDD的循环非常适应为止。否则,就像参加了一场没有技术水平的比赛。
什么是TDD(一)的更多相关文章
- TDD在Unity3D游戏项目开发中的实践
0x00 前言 关于TDD测试驱动开发的文章已经有很多了,但是在游戏开发尤其是使用Unity3D开发游戏时,却听不到特别多关于TDD的声音.那么本文就来简单聊一聊TDD如何在U3D项目中使用以及如何使 ...
- 初步认识TDD
TDD,测试驱动开发(Test Driven Development)是极限编程中倡导的程序开发方法,以其倡导先写测试程序,然后编码实现其功能得名.本文将对TDD有一个较为系统的认识. 基础属性 ...
- Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记
0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...
- TDD原则
TDD 介绍 测试驱动开发,或者叫 TDD,是一个敏捷方法,通过确保在代码是先前手动编写测试用 例,用测试来驱动开发,从而翻转开发生命周期(它不只是作为一种校验工具). TDD 的原则很简单的: 只有 ...
- 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 ...
- 使用IdleTest进行TDD单元测试驱动开发演练(3) 之 ASP.NET MVC
一.[前言] (1)本文将用到IOC框架Unity,可参照<Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备>(2)本文的解决方案是基于前述<使用I ...
- 使用IdleTest进行TDD单元测试驱动开发演练(2)
[前言] 1. 有关上篇请参见<使用IdleTest进行TDD单元测试驱动开发演练(1)>,有关本篇用到Entity Framework Code First请参见<使用NuGet助 ...
- 使用IdleTest进行TDD单元测试驱动开发演练(1)
[前言] 开发工具:Visual Studio 2012 测试库:Visual Studio 2012自带的MSTest DI框架:Unity 数据持久层:Entity Framework 前端UI: ...
- 前端自动化测试 —— TDD环境配置(React+TypeScript)
欢迎讨论与指导:) 前言 TDD -- Test-Drive Development是测试驱动开发的意思,是敏捷开发中的一项核心实践和技术,也是一种测试方法论.TDD的原理是在开发功能代码之前,先编写 ...
- TDD学习笔记【四】--- 如何隔离相依性 - 基本的可测试性
前言 相信许多读者都听过「可测试性」,甚至被它搞的要死要活的,还觉得根本是莫名其妙,徒劳无功.今天这篇文章,主要要讲的是对象的相依性,以及对象之间直接相依,会带来什么问题.为了避免发生因相依性而导致设 ...
随机推荐
- shell脚本(15)-sed命令
文档目录一.sed-简介1.shell对文件操作介绍2.sed命令简介3.sed语法: sed [options] '{command}{flags}' [filename]二.sed-命令选项( - ...
- Angular系列教程之自定义指令
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
- [转帖]jmeter 响应时间rt很小,但是tps也很小&jmeter,脚本处理,千万不要用js
一.背景: 在压测的时候,查看jmeter聚合报告,发现rt很小,但是tps也很小. 讲道理来说,响应时间越小,tps应该越大. 一共压测10分钟,发现jmeter请求的样本数量非常小,才8500个请 ...
- [转帖]iptables ip_conntrack_max 调整
https://www.diewufeiyang.com/post/583.html 一.概念 ==================== -允许的最大跟踪连接条目:CONNTRACK_MAX(默认值是 ...
- Java火焰图简单学习
前言 立的flags倒了太多次 自己还是太菜了.. 课题太大, 自己简单总结一下. 要是自己总结错了. 就不收费, 错就错了 !-_-! 第一步准备环境 一定要设置对java的HOME以及PATH路径 ...
- linux线程调度策略
linux线程调度策略 这是一篇非常好的关于线程调度的资料,翻译自shed 目录 linux线程调度策略 Scheduling policies SCHED_FIFO: First in-first ...
- SUBMIT指定用户名错误
1.SUBMIT说明 在ABAP中,SUBMIT关键字用于运行另一个ABAP程序.通过SUBMIT关键字,可以在当前程序内部调用其他程序,而无需关闭当前程序. SUBMIT语句的一般语法如下: &qu ...
- 2024了,我不想再用AOP收集业务操作日志了 | 京东云技术团队
0.背景 在近期的项目中,系统涉及到针对系统的业务操作日志统计功能,由于本系统位于业务链路的中心环节,负责接收上游系统的数据,并将基于用户操作产生的数据传递至下游系统,鉴于业务链路的复杂性和操作场景的 ...
- vue新一轮的面试题
参考的连接: https://juejin.cn/post/6844903876231954446 1. 在vue中watch和created哪个先执行?为什么? 在wacth监控数据时,设置imme ...
- 基于密码学的身份混淆系统 -- idmix
简介 Hyperledger Fabric的Idemix是一个基于密码学的身份混淆系统,它提供了一种在区块链网络中实现用户隐私的方法.Idemix的主要特性是它的零知识证明系统,这是一种允许用户证明他 ...