TDD(测试驱动)调研

一、认识TDD

1.概念

测试驱动开发(Test Driven Development, 简称TDD)是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写测试用例代码,测试代码确定需要编写什么产品代码。
TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。可以帮助我们增量式的构建系统,也能保证代码在任何时刻都不会错的离谱。

2.问题背景

1.糟糕的代码质量

1.缺陷带来额外的开销,软件的不稳定。
测试阶段修复一个问题通常是开发阶段修复这个缺陷的成本的两倍或者更多。
2.维护困难,开发缓慢
糟糕的代码,阅读困难,维护性差,扩展困难。

2.不能满足需求

开发出的功能和需求有差异,交付时才发现,费时费力。

3.TDD优点

1702534487774.jpg

1.不再长时间调试代码

TDD的方式写代码,把开发过程分解为小的、集中的测试,遇到的问题很快定位,几乎不需要调试定位问题。

2.对完成的工作很有信心

使用TDD不能保证一个BUG都没有;但是可以让人对自己开发的代码有足够了解,取决于测试代码书写的规范程度。
测试越好,代码质量越高,对代码改动越有信心。

3.有更多时间做其他事情

TDD和ADD并不会提高我们敲键盘的速度,但能缩短由于低效开发方式(例如调试代码,理解可读性不高的代码,或因为误解需求返工)所浪费的时间。
总体来讲:TDD是设计和开发方法,它能帮我们从项目开始就构建出可运行的软件,以增量的方式添加新的功能,使软件在整个开发过程中都能工作良好。通过演进式设计,并且应用重构优化每一步的设计,我们可以防止代码质量随着时间的推移而下降。

二、TDD的组成

1.TDD周期

测试->编码->重构

TDD周期.png

  • 在代码层次,在编码之前写测试脚本[红、绿、重构]。
  • 操作流程:
    • 写一个测试用例
    • 运行测试
    • 写刚好能让测试通过的实现。
    • 运行测试。
    • 识别坏味道,重构。
    • 运行测试。

2.增量式开发

增量式演化设计是指在系统不断添加更多的功能和行为的过程中,不断地微调代码结构。在代码生命周期的任何时刻,代码所展示的都是开发人员为完成现有功能所做的最好的设计。我们只为完成当前功能而设计,而不会试图事先做完所有设计。按照开发过程中获取到的信息调整当前设计,而不是在项目一开始的所谓设计阶段企图预见到所有应用场景,然后基于这些或实或虚的假设做设计。
1.小步增量
在迭代、增量式的开发过程中 ,我们需要不断地在“实现新功能”和为支持新功能而“调整设计乃至架构”两项任间切换。
image.png
将大的开发任务,拆分成小的具体的任务。对应的到代码就是一个个测试。完成每一个测试就是完成每一个阶段性的目标。
2.演进式的设计
恰如其分的满足需求。
image.png
image.png
3.时刻保证软件可用
image.png

3.小步重构

  1. 先做容易的功能。
  2. 消除测试中的重复。
  3. 安全的替换实现。
  4. 使用新的实现。
  5. 保持统一的抽象层次。
  6. 通过抽取函数来清理代码。
  7. 把逻辑重构到对象中

4.TDD的重要概念和模型

1.重要概念:

夹具(fixture)
测试替身(test doubles)
伪实现
测试桩
模拟对象
基于状态的测试
基于交互的测试

2.测试选择技巧

  • 细节与整体

深入细节与整体考虑,根据具体情况选择。

  • 不确定与熟悉

减少不确定性,或者优先选择熟悉的测试。

  • 高价值与现成果实

优先选择工作量少,回报却最多的测试。

  • 基本功能和出错情形

根据价值和容易程度判断优先选择哪个测试。

3.测试通过,实现技巧

  1. 伪实现

由于优先级或者其他原因,我们可能会伪实现某个功能,使测试尽快回到绿的状态。

  1. 三角法

类别三角定位法。在实现一个复杂测试时。可以先实现多个已知的测试,然后重构,及是复杂测试的逻辑代码。

  1. 显而易见的实现

大多测试的实现是显而易见的,可以直接实现。

4.测试驱动的基本准则

  1. 绝不跳过重构
  2. 尽快变绿
  3. 犯错后减慢速度

5.重要的测试概念

夹具是测试的上下文

夹具定义为测试类中所有测试方法共有的初始条件。

  • 1.状态概观

夹具是整个运行时的状态。

  • 2.夹具可消除重复

夹具把多个测试共享的状态移至一处,有效的消除重复。避免光板夹具,及每个测试方法重头创建夹具,各个测试的初始化毫无共性。

  • 3.夹具使测试更紧凑
用测试替身替换依赖

测试中依赖其他对象的协作,可以使用替代方法实现,同时不牺牲质量、速度、效果,这种替代方法叫测试替身。测试工具会协助生成测试替身。

基于状态及基于交互的测试

测试替身可分为两类:基于状态的测试以及基于交互的测试。
1.基于状态的测试
2.测试交互
3.各种方法的测试范围

近处观察测试替身

有时我们并不希望在测试中使用真实的类,原因可能有几种:

  • 太慢
  • 目前尚不存在
  • 其依赖的东西并不存在
  • 很难实例化,为测试配置状态也不容易。

1.伪实现、测试桩和模拟对象
image.png

提高设计的可测试性的准则
  • 尽量使用组合而非继承
  • 避免使用static关键字,以及singleton模式
  • 隔离依赖
  • 注入依赖
单元测试模式

单元测试是TDD中的重要一环。单元测试的常用模式包括如下。

  1. 写断言的模式
  • 结果状态验证
  • 防卫断言
  • 差值断言
  • 自定义断言
  • 交互断言
  1. 夹具的模式
  • 参数化创建方法
  • 对象母亲(对象工厂)
  • 自动清理
  1. 测试模式
  • 参数化测试
  • 自分流
  • 无间内部类
  • 特许访问
  • 额外构造函数
  • 测试专用子类

三、TDD的延伸

1.ATDD

验收测试驱动开发,测试驱动开发核心理念的一个扩展。在用测试驱动开发之前,我们将首先编写功能测试或验收测试,从系统功能角度驱动开发过程。
尽管ATDD很像TDD,也借鉴了TDD的许多优点,但这两种开发方法可以分开使用。不使用用户故事的开发人员,或者实现功能前不先写测试的开发人员,仍然可以使用TDD。那些不用测试先行的方式写代码的团队,仍然可以用ATDD测试先行地实现新功能。这些技术互相弥补互相支撑,结合使用时更能发挥作用。

2.ATDD与TDD的关系

image.png

  • Discuss: 各个角色一起参与,保障对需求用例(User Story)有一致的理解;避免开发完之后不满足客户需求的情况。
  • Distill: 需求的提取和拆分,也就是将需求分解成开发人员和测试人员都能理解,切认可的最小单元。
  • Develop: 通过单元测试驱动开发,即上面周期(红-绿-重构)的循环。
  • 开发根据(FIT)需求描述语言进行开发设计,测试根据需求描述语言来写验收测试用例。
  • Demo: 验证阶段,团队成员向产品负责人和客户演示完成的功能, 验证的时候直接执行(FIT 集成测试)需求,从而验证需求是否被实现。

三、TDD的落地

1.TDD工具

  • junit工具:java单元测试,自动测试
  • SpringBoot-test:集成junit,支持单元测试和集成测试。

2.ATDD工具

Fit:可以帮助需求定义人员与开发人员进行沟通,以实现自动化验收测试,进而保证完成足够的回归测试.
FIT通过一张表格式的需求描述,很好地体现了关键字驱动脚本和数据驱动脚本的完美结合
apiFox:可以配置自动化测试,配置测试场景。生成测试报告。兼容其他的测试工具,可以自动导入(Swagger)Api。

3.好的测试规范

java开发规范中测试的规定。
image.png
image.png

四、TDD的不适合的场景

软件开发领域常讲“没有银弹”,同样TDD也不是银弹;很多开发团队无法执行TDD, 总结几方面的内容:

有些场景并不适合TDD方式

总结而言,不符合迭代开发的或者无法进行对应的快速测试的场景不适合TDD方式开发。

  1. 无法迭代开发的

适合迭代的都是具体的需求实现,对于整体系统的设计是不适合迭代的,也不适合用用测试驱动开发。
因为后续的重构会对之前的代码逻辑有冲击,迭代将带来的持续冲击式重构,这种常见下的测试驱动开发对开发者而言是一种灾难。
比如复杂算法的实现,举个例子,你现在要开发一个傅里叶变化的模块,输入一些数据,得到傅里叶变换的结果。你花了一些时间,看懂了傅里叶变化的公式,对其实现也有把握,但是在写断言的时候就发现结果的验证太困难了,你可能需要借助matlab或者python来预先得到结果,然后复制结果到断言中。
数据驱动的算法也无法用TDD来开发,例如机器学习、深度学习。因为其结果与数据相关,当数据发生变化时,算法行为也会发生变化,这就没法写测试用例了。

  1. 无法快速测试的

测试驱动开发的另外一个必要条件是每次的迭代是可以被快速验证的,如果无法快速测试,那么就不适合。

  1. 存在交互边界的

比如硬件的开发,因为存在物理的边界。

TDD对团队本身有一定的要求

  1. 团队对质量管理的要求和认同

测试驱动开发只是一种敏捷开发方式,它是将测试提升到与开发同等重要的位置,以保证在敏捷的迭代开发中保持软件的质量。有些团队没有完善的软件开发质量体系和资源,没有将质量规范融入到整个开发流程中(也没有专人或团队来约束规范),甚至团队生存都存在问题,追求短平快更不会关注质量(@pdai: 想起一句经典台词:我都混到吃泡面了,我还在乎健康?);在这些情况下团队对质量管理缺乏认同,对开发测试的工作就变成了负担。

  1. 团队对需求和任务拆分的能力

测试驱动开发有一个很重要的前提条件是有相对可迭代开发的拆分需求,所以团队对需求的理解以及任务的开发能力极为重要,拆分任务时需要对任务的粒度和可持续性有较高要求;频繁需求的变更和拆分不到位,将让驱动测试开发陷入疲于奔命。

  1. 团队对重构的理解和能力

重构对于测试驱动开发是极为重要的,正如上面的例子看到的,在后续的用例需求开发时需要对前面的开发代码进行必要的重构,以满足当前的代码是满足相对最佳实践的;此时你可能会发现,增量写的用例需要对前面写代码大幅度的重构,而这些代码可能不是你写的,所以在团队没有对重构有统一的理解或者缺乏对重构的把控时,测试驱动开发可能会成为一种负担。

  1. 团队对协作的理解和能力

一个团队中是有很多角色的(产品负责人,PM,架构,开发,测试等),测试驱动开发不仅仅是开发者要做的事情,而需要其它角色的协作。举个简单的例子,如果在必要时候后续开发需要对之前代码进行重构,但是产品负责人或者PM无法认同,认为只是一个平行功能的开发,没有给到开发者足够的重构时间,这时便会错失好的重构时间点,对后续整体质量将埋下一个坑,而且这种技术债务有一天是要还的。

五、TDD的研究文献

有关TDD的有效性和成本已经有很多研究了。下表是个总结

作者/年份重要发现
Siniaalto,2017在新窗口打开TDD不总是能提高开发效率,特别是在对TDD不熟悉的情况下。但是TDD所生产的代码具有更高的测试覆盖率。
Neil,2017在新窗口打开github上使用TDD开发的Java项目非常少,将TDD开发的项目与其他项目进行对比,并没有发现TDD开发的项目有明显的优势。
Wilson,2016在新窗口打开TDD能够生产更好质量的代码,但是开发效率不如TLD(开发完再测试)
Davide,2016在新窗口打开TDD声称的好处可能不是由于其独特的测试先行产生的。但类似于TDD所鼓励的细粒度稳步的增量式开发,可以改善开发质量
Nagappan, 2008在新窗口打开TDD消除缺陷是40% ~ 90%,其成本在开发初期多出15% ~ 35%
Sanchez,J.C,2007在新窗口打开TDD产生的缺陷密度低于行业标准。TDD或许能减少代码复杂度随着软件年限而增长的程度
Bhat,2006在新窗口打开TDD的使用可以让代码质量提升,初始成本增加至少15%
Siniaalto,2006在新窗口打开有些情况,TDD会大幅度提升效率,大概在2/13的情况下回减低生产效率(但会提升代码质量)
George,2003在新窗口打开TDD开发的代码质量更好(可以多通过18%或者更多的功能测试),且多用16%的开发时间。事后测试的代码测试不够充分

参考资料

[测试驱动开发的艺术].(科斯科拉).李贝.pdf
测试驱动开发.pdf
详解测试驱动开发 Test Driven Development(TDD)
测试驱动开发(Test-Driven Development)
测试代码的坏味道 - Phodal | Phodal - A Growth Engineer
SpringBoot的集成测试与单元测试-CSDN博客
构建自动化测试框架
聊聊测试驱动开发 · TesterHome
用FIT 集成测试框架进行确认测试.docx
Fit相关工具下载
【敏捷开发】
敏捷开发 - 开发实践:测试驱动开发(TDD)
JUnit 5 用户指南

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哼哼牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值