TDD实践和思考

1. 前言

敏捷开发是现在被广泛应用的软件开发方法,强调程序团队成员与业务人员紧密协作,频繁交付新的软件版本。

敏捷软件开发法支持广泛的软件开发生命周期。有的专注于实践(例如,极限编程、务实编程,敏捷建模),而有的专注于管理工作流程(例如Scrum,看板)。有的支持需求规范和开发(例如FDD)的活动,而另一些则试图涵盖整个开发生命周期(例如DSDM,RUP)。

我这里准备介绍极限编程实践中的测试驱动开发(Test Driven Development 简称TDD)。

2. TDD介绍

关于TDD的详细介绍可以看这篇文章:深度解读 - TDD(测试驱动开发)

单纯看文字可能比较难理解TDD执行的过程,这里还有该作者录制的视频,能够更加直观的了解TDD开发过程。TDD - Word Frequency。使用2倍速观看效果更加。

接下来我还是简单的介绍下TDD的基本概念和核心观点吧。

2.1 概念

测试驱动开发(英语:Test-driven development,缩写为TDD),是一种软件开发过程的应用方法,在极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名。

TDD 有广义和狭义之分,常说的是狭义的 TDD,也就是 UTDD(Unit Test Driven Development)。广义的 TDD 是 ATDD(中文:验收测试驱动开发,英文全称:Acceptance Test Driven Development),包括 BDD(中文:行为驱动开发,英文全称:Behavior Driven Development)和 Consumer-Driven Contracts Development (消费者驱动) 等。

本文所说的 TDD 指狭义上的 TDD,也就是「单元测试驱动开发」。

2.2 TDD核心观点

TDD核心观点是先写测试,后写业务代码, 以通过测试作为开发的辅助项,多次低成本的重构业务代码,达到编写高质量代码的目的。

TDD编码流程:

  1. 任务分解
  2. 确定测试用例
  3. 使用TDD基本流程开发

TDD基本流程
TDD实践和思考_第1张图片
TDD基本流程为:红,绿,重构。

  • 红:代表先写的测试未通过(这是肯定的,业务代码都没写)
  • 绿:说明写业务代码让测试通过
  • 重构:检查刚才写的业务代码,设计是否合理

TDD通过不断的重构达到优化代码的效果,并且这些重构并不会浪费很多时间,相反,使用得当还能比传统编码更省时并且代码质量更高。

对于TDD的详细介绍我就不再叙述,毕竟别人已经写了很好很详细的介绍文章,如果不了解TDD的可以看这篇文章:深度解读 - TDD(测试驱动开发)

3. TDD实践

知道了TDD这个编码实践,我当然迫不及待的自己使用看看效果如何。这里我用自己做的项目做一个尝试,选择了一个跟用户相关的业务,下面是详细的实践过程:

1. 需求

增加用户,实体类为user,增加时需要数据为:用户名(英文字母和数字),密码,角色(数字)

2. 业务流程

  • 参数校验
  • 查看数据库中用户名是否存在,如存在则返回增加失败
  • 用户名没有被注册,增加用户
  • 增加成功

3. 测试用例

  • 参数校验测试:各种不符合规范的参数、符合规范的参数
  • 用户名存在测试
  • 成功添加测试

4. 使用TDD编码

因为我负责的是一个web服务器,遵循mvc架构模式,项目中最少有三层逻辑:控制层(controller)、服务层(service)、数据持久层(dao)。在mvc模式下,上述的测试用例以控制层为测试目标。

1. 测试用例:参数校验测试

用户名校验

  1. 先写一个含特殊符号的用户名,此时服务器返回信息应该是"用户名格式错误"
  2. 写业务代码,正确校验用户名

密码校验

  1. 写一个长度超过的密码,此时服务器返回信息应该是"密码格式错误"
  2. 写业务代码,正确校验用户密码

因为参数校验步骤都差不多,这里不再啰嗦。当然,实际编码不需要一个个的写,可以一下子写完所有的参数校验,然后批量测试。如果每个接口参数校验都要一个个写,这就有点不懂变通了。毕竟TDD是一个编码思想,还是要配合自己的开发节奏来走。

2. 测试用例:增加用户时用户名存在

  1. 现在数据库中手动输入一个用户
  2. 编写测试用例,输入给定正确格式的用户参数,此时服务器返回信息应该是"用户名已存在"
  3. 编写业务代码
    1. 写服务层接口
    2. 写根据用户名查找用户接口
    3. 在服务层判断用户名是否存在,如果存在返回错误信息(业务逻辑代码写到这里就可以满足测试用例,剩下的插入用户的代码不用着急写)
  4. 通过测试
  5. 审查代码是否需要重构

上述过程已完成用户名存在这个测试用例,接下来剩下成功添加用户了

3. 测试用例:增加用户时用户名存在

  1. 编写测试用例,输入给定正确格式的用户参数,此时服务器返回“成功添加用户”
  2. 编写业务代码(在检查完用户名是否存在下面加入添加用户的逻辑代码即可)
  3. 通过测试
  4. 审查代码是否需要重构

上面是一个简单的使用TDD开发的过程,我在使用的时候感觉挺繁琐的,毕竟如果不写测试,这种简单的逻辑我三下五除二就写完了,哪还有这么多事。不过,仔细观察,我感觉TDD还是挺不错的,它最重要也最好用的就是每个测试用例的最后一步:检查代码是否需要重构。一般而言,如果功能比较复杂的,可能每经过一个测试用例代码都需要稍微重构一番,这可是最低成本的重构,不会浪费很多时间,而且思路也很清晰。我觉得这就是TDD吸引我的地方了。当然,TDD还有其他的好处,不过目前我没体会到。

4. 使用TDD思考

TDD只是敏捷开发中的一个开发实践,并不是银弹,不是所有项目都适合的。而且TDD是一个非常广泛的概念,它不仅仅指单元测试,在项目架构设计和其他方面也有适合的场景。

在短暂的使用TDD开发的过程,我感觉TDD有它的优点和局限性:

优点:

  1. 任务分解会使逻辑更清晰
  2. 可以小步试错,以最低成本重构代码
  3. 以测试用例为驱动,可以边测试,边重新设计代码结构

缺点:

  1. 任务分解的度不好把握,要分多细致才合适
  2. 在一些简单的业务逻辑上显得特别繁琐
  3. 一些复杂的业务不仅业务代码需要多次重构,可能因为业务过于复杂,测试用例也需要多次调整
  4. 需求变更时,测试代码也要跟着维护

上述是我个人使用TDD后总结的一些优缺点,当然还有其他的,需要各位自行体验了。

5. 总结

个人感觉传统的TDD不是很适合如今的开发节奏,毕竟现在开发时间都比较紧迫,需求也会经常变动,这样就没那么多时间使用TDD进行开发。当然,如果是一些比较复杂的场景,使用TDD可能事半功倍。总的来说如果要使用TDD,要考虑以下问题:

  1. 项目是否适用于使用TDD开发
  2. 学习使用TDD的时间和精力成本
  3. 写测试代码和需求改变时测试代码的维护成本
  4. 是否能够正确分解任务需求
  5. 测试用例是否真正的促进了开发进度和提高代码质量

你可能感兴趣的:(TDD实践和思考)