TDD基础-为什么关心测试驱动开发

随着工作中写的代码越来越多,见的代码越来越多,逐渐产生了什么样的代码是好的代码,如何评判代码的好坏,代码质量如何保证等等问题,前者通过Clean Code的不断实践,有了不错的码感,后面有机会单写文章谈谈这部分;后者一方面由于遇到的项目甚至一些开源项目在质量保证这方面做的都不足,导致没有学到一些好的实践,另一方面实在受不了自己的工作中充斥着低质量且无法验证的代码,因此尝试实践TDD,通过TDD找到一些解决办法,本系列文章为在实践过程中的一些总结。

1 Why TDD

不管基于什么样的流程规范,在我们日常开发中总会遇到如下痛点、问题导致延期或项目交付失败:

  • 部分团队成员无缘参与需求、规范或用户故事的制定;
  • 大部分乃至全部测试都是手动的,抑或根本就没有测试;
  • 虽然使用了自动化测试,但并未检测出真正的问题;
  • 编写并执行自动化测试的时间太晚,无法给项目带来真正的价值;
  • 总是有更紧急的问题需要处理,没法腾出专门用于测试的时间;
  • 整个团队分为测试、开发和功能分析小组,而这些小组常常不能同步;
  • 无法重构代码,因为担心这样做会破坏既有的功能;
  • 维护成本高;
  • 开发与上线时间脱节;
  • 业务觉得交付的产品不符合要求;
  • 文档从来都不是最新的;
  • 团队为搞清楚某些方法或类的作用花费的时间太多

测试驱动开发不是银弹,并不能解决所有的以上问题,但为我们解决问题提供了一个方向,TDD的开发实践能或多或少的对这些情况进行改善,简化重构、提供有效的逻辑验证、帮助创建更好的方案设计、降低代码耦合度、提高代码质量、提供代码文档、获得较高的测试覆盖率等等。

然而要掌握TDD并不容易,需要学习理论知识并进行大量实践、甚至我认为TDD的核心之一是持续创建高效高质量测试,而其实现方法有很多,并且随着技术的发展相信还会有越来越多更好更便捷的实现方式。虽然需要付出这么多的成本,但带来的好处是极大的,随着实践的增多,你的代码会变得越来越好,你的码感也会越来越有质量,项目中的同学会越来越喜欢你写的代码。

学习编程技巧最好的方法就是实践、实践是检验真理的唯一标准,下面将介绍一些基础知识,在熟悉基础的理论和掌握了基本的工具后,剩下的就需要不断地practice了,想到获得更多的TDD经验,就需要在日常工作总不断地使用总结-优化实现-总结。

1.1 理解TDD

TDD是什么,TDD是一种简单的流程,要求先写测试,再编写实现代码,与传统编写代码后再测试相反。

1.2 红绿重构

TDD是一个过程,一来不断重复极短的开发周期,基于XP的测试优先理念,倡导采用可高度信赖的简单设计,驱动这个过程前行的开发周期称为“红灯-绿灯-重构”。该流程由几个反复进行的步骤组成:

  1. 编写一个测试
  2. 运行所有测试
  3. 编写实现代码
  4. 运行所有测试
  5. 重构
  6. 运行所有测试

以上流程中第一步由于测试是在实现前编写的,因此应该通不过,如果通过了,说明测试是错误的,要么其功能已经存在,要么测试写的不正确,应该进行删除或重新设计;如果最后一个测试未通过,说明实现不正确,需要修正;如果其他测试未通过,说明我们破坏了某种功能,需要撤销所做的修改。这种情况下,一种更自然的反应是花时间修复问题,然后TDD提倡如果不能在短时间内,如几分钟修复问题,更好的方式是撤销所做的修改,因为新的实现带来了破坏,所以更好的方案就变成相应的回到原来正常的情况下,重新考虑实现方案,这样我们在错误的方案下浪费的时间就很少,避免在修复一开始就不正确的方案上浪费更多时间。

还有一点值得提醒的是不要试图让实现完美无缺,而应只编写足以让这个测试通过的代码。

我们编写代码要快,目的就是快速的进入绿灯状态,因为一旦进入绿灯状态,我们就知道存在一个由测试构成的安全网,可以接着放心的重构代码,改进优化代码。当然在测试期间不应该引入新的功能,以避免测试代码无法覆盖,导致安全网失效。重构-测试-重构-测试,这是一个无限loop,每次loop应该都是一个很短的周期。多短?我想大概是按分钟计或更短吧

1.3 TDD并不只是测试

TDD是一种设计方法,在编写代码之前考虑实现以及需要提供的功能,且每次主管朱一项功能的需求和实现,以此来帮助理清思路以及更好的组织代码,同时TDD编写的测试,以其快速高效执行的特点,帮助我们有条不紊的重构,对需要时长修改的代码大有裨益。TDD的主要目标是提供可测试的代码设计,测试是其提供的非常有用的副产品。

1.4 更好的测试

测试方法有黑盒白盒测试,适用于不同场景不同角色,不管是哪种测试,编写测试的顺序都非常重要,需求是在实现需求的代码之前编写的,因此是他们定义了代码,而不是代码如何实现决定需求要如何提(虽然企业中有很多这种代码定义需求的case)。对测试来说也是这样,如果在代码之后编写测试,那么就变成了代码定义了测试,用已有功能定义的测试可能更倾向于确认代码功能,而不是检查用户的需求是否实现。

2 MOCK

要让测试快速运行,且不断提供反馈,必须以合适的方式组织代码,以便能轻松的mock对象,stub方法、函数和类,外部依赖可能会严重影响执行速度,日常工作中常遇到的,一来数据库、spring容器、中间件等,通过模拟外部依赖,可以极大提高速度,更轻松的测试才会趋势你更多的去使用,要达到轻松的mock和stub,就必须分离关注点,解耦依赖。

3 可执行文档

TDD(以及更多结构良好的测试)另一个很有用的方面是文档,搞清楚代码是干什么的, 在大多数情况下通过查看测试比查看实现本身要容易得多。传统软件文档存在的主要问题是,它们通常都不是最新的。一部分代码发生变化后,文档便不再反映实际情况。几乎任何类型的文档都如此,需要为代码编写文档通常意味着代码本身写得不好。另外,不管你如何努力,文档都必然会过期,开发人员不应依赖于系统文档,因为它几乎在任何时候都不是最新的。另外,在详尽而及时地描述代码方面,没有任何文档比代码本身做得更好。talk is cheap,show me the code。将代码用作文档并不意味着不能有其他类型的文档,关键是避免重复。如果说通过阅读代码 可获悉系统细节,那么其他类型的文档可提供快速指南和概述。非代码文档应回答诸如“系统的 总体目标是什么”“系统使用了哪些技术”等问题。大多数情况下,简单的README足以提供开 发人员所需的快速入门指南;对新来者而言,项目描述、环境搭建、安装以及构建和打包说明等 部分很有用。至于其他方面,代码就是“圣经”。实现代码提供了所需的所有细节,而测试代码描述了产品代码背后的意图。

4 无需调试

在编写代码前编写测试且代码覆盖率很高的情况下,我 们完全可以相信应用程序将像预期的那样工作。这并不意味着使用TDD编写的应用程序没有 bug——bug肯定是有的,所有应用程序都有bug;但出现bug时,可轻松地找出它们——只需查看 未被测试覆盖的代码即可。

总结

好了,TDD相关的一些的基本想法就介绍到这里,后面尝试扩展开来给大家介绍下如何实践。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值