更好地做UTDD(测试驱动开发)

更好地做UTDD

前言导入

        通过前面对UTDD内容的介绍,我们也基本熟知UTDD的基础知识,也动手进行了实践,这算是正式开启了UTDD之旅。
        同时,新的问题也随之而来了:“如何更好地做UTDD呢?”。同样,我们可以分为 理论、实践两部分进行提高。

理论

理论引言

        我们已知道UTDD的基本流程:红 -> 绿 -> 重构,一个完整闭环;并且整个软件开发过程是由一个个UTDD基本流程 组成
        若我们想更好地做UTDD,那么我们能否从其基本流程入手呢
        答案:是可以的。那让我们一起来回想 “红” 代表什么?让程序运行失败的单元测试用例。 那”绿“ 又代表什么呢?填充让程序刚好通过用例的程序逻辑代码。最后,“重构”字如其意,代表着 更加整洁的单元测试用例、程序逻辑代码。

红——单元测试用例

什么是单元测试

     既然要写 单元测试用例,那么第一步应该正确认识 “什么是单元测试?”

  • 在过程式、函数式编程者眼中,一个单元可能是单个程序、函数、过程等。
  • 在面向对象编程者眼中,下至一个方法,上至一个类都可能是一个单元。

    既然 众说纷纭,那么一起来看看 官方定义

  • 计算机编程中,单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块软件设计的最小单位)来进行正确性检验的测试工作。 (来自维基百科词条)

  • 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。

  • 初看官方词条时,我能感觉它说得正确,但是 我理解不了!(究其原因,为了解释这么一个名词抽象概念,又引入好些对于我们而言,陌生的名词抽象概念,加大了我们的理解难度。)

   既然 难以理解官方定义,那么尝试对其进行 通俗解释:

  • 既然我们写单元测试用例,是为了 “验证 程序逻辑代码 是否按预期运行”。

  • 而所谓 单元测试“单元”的粒度,取决于 我们 想验证的程序逻辑代码的粒度,可以是 一个函数、方法、类等;关键取决于 我们的 “测试意图”(灵感来源于 意图编程)。

  • 所以,单元测试用于测试一个独立的工作单元的执行结果是否符合预期。

单元测试测哪些内容

     已经知道了什么是单元测试,那下一步就该了解 “单元测试测哪些内容?” 已知单元测试是一个更加细化、具体的测试分类,那么测试相关的理念方法论也同样适用于 单元测试

   Right-BICEP

  • Right——结果是否正确?

  • B——是否所有的边界条件都是正确的?

    • 找边界条件是做单元测试最有价值的工作之一,因为bug一般就出现在边界上。

    • 一个帮助想到可能的边界条件的办法就是助记短语CORRECT

  • I——能查一下反向关联吗? 对于一些方法,我们可以使用反向的逻辑关系来验证它们。

  • C——能用其他手段交叉检查一下结果吗?通常而言,实现一个工作单元有一种以上的算法。我们选用其中一种最好的来作为我们的代码实现,但可以使用其余的算法来作为单元测试。

  • E——你是否可以强制错误条件发生?在真实世界中,错误总会发生:磁盘会满,WIFI会断开,程序会崩溃。你应该能够通过主动强制引发这些错误,来测试你的代码在这样极端状态下是如何应对这些真实世界中的问题的。

  • P——是否满足性能要求?

单元测试的优秀品质
      光掌握单元测试应该测哪些内容是远远不够的,正所谓 见贤思齐,让我们一起来看看优秀的单元测试应具备哪些品质:FIRST原则

  • Fast(快速的):测试要非常快速,每秒要能执行几十或上百个。这样开发人员可以对每一个小更改运行测试,而不用中断思绪去等待测试运行。

  • Isolated(独立的):测试应该能清楚地隔离一个失败。一个测试不会依赖另一个测试。不同测试的故障是相互隔离的。

  • Repetable(可重复的):测试应可以重复运行,且无论执行多少遍,结果都是一样的

  • Self-verifying(自我验证的)测试要无歧义地表达成功或失败

  • Timely(及时的)测试用例必须及时编写、更新、维护。

绿——程序逻辑代码

    目前尚未整理,建议采用 DDD(领域驱动设计)思想,写出 “充血模型”对象,而不是“贫血模型”对象;可自行参考《领域驱动设计》《领域驱动设计精粹、解构领域驱动设计》等书籍。

重构—— 更加整洁的代码

   目前尚未整理,可自行参考 《重构》、《代码整洁之道》等书籍。

实践

实践引言

        “纸上得来终觉浅,绝知此事要躬行。”
        同样,实践可以与理论对齐,也从UTDD流程:红->绿->重构,一个完整闭环入手。

红——单元测试用例

 一图胜千言        

         图片来源于《有效的单元测试》,这张图是作者从工作实践中总结提炼而成的图;我们可以从 这张图入手 在实践上达成  “更好地做UTDD"目标。
        从图片可知,有关单元测试方面,我们可以从 测试的执行速度测试的可读性测试的可维护性测试的可靠性等几个方面入手。

测试的执行速度
        怎么样能提高测试的执行速度?减少或不依赖 相关外部基础设施、组件、spring容器等!          
若能结合领域驱动设计思想,采用领域驱动框架,我们只需对 领域层 进行单元测试即可。
补充说明:领域驱动框架的领域层  用于存放 领域模型,为了保证 领域层的纯粹性,而不会直接依赖相关的外部基础设施、组件、spring容器。

测试的可读性
        若是将测试代码比作一份文档(扩展参考《活文档》),那么问题就变成了 “怎么让文档更具有可读性?”。依据个人理解,我们可以从规范化、结构化两方面入手。


        规范化:1、单元测试方法仿照Ruby语言的方法进行命名,且方法名应表达出 “测试意图”示例:firmNumer_cannot_be_null_or_empty。 其他代码细节规范,可参考《阿里编码规约》。
        结构化:善用Junit5的新特性 @Nested @DisplayName
       简单地说,@Nested解决了随着Case越来越多,Case管理的问题;可用于将测试结构化

测试的可维护性
       
若是能做到上述的 “测试具有良好的可读性”,那么此时也基本能做到 “测试具有一定可维护性”。若想测试的可维护性更进一步,需要引入 “数据夹具”
        个人理解,单元测试无非是构造场景数据,紧接着使用场景数据验证预期逻辑。
        数据夹具 实际上是为测试准备一系列状态对象工具类
        借助数据夹具一是可以有效消除重复代码(同时也方便维护)、二是能极大调用开发者的情绪。(我们只需传几个关键参数,剩下的不关注信息由数据夹具替我们默认填充,由数据夹具统一返回预期对象。)

测试的可信赖性
        1、
测试方法名显示的测试意图 必须与 方法具体实现 一致。(禁止 答非所问)
        2、禁止 测试用例没有断言(没有断言的测试是毫无价值的)

绿——程序逻辑代码

重构——更加整洁的代码

更多文章,请移步至:https://blog.csdn.net/qq_41998273/category_11699499.html

参考文章

《测试驱动开发》作者:Kent Beck
《测试驱动开发的艺术》作者:科斯凯拉 (Lasse Koskela)
《有效的单元测试》作者:科斯凯拉 (Lasse Koskela)
《解构领域驱动设计》作者:张逸
《活文档与代码共同演进》作者:Cyrille Martraire

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值