摘要
单元测试是保证代码质量的一个非常有效的手腕。但在单元测试理论中,往往会呈现研发人员不愿意写单元测试,或者即便写了单元测试,但是其代码质量和覆盖率不高的问题。本文会尝试分析单元测试推广难,质量差的原因,并给出一个处置之道。
单测推广难点
研发人员为什么还是不愿意写单测呢?常见的主要有以下几个原因:
- 虽然这代码是我写的,但是~~质量不好,~~很难测
- 因为这代码是我接手的,所以质量不好,很难测
- 我只改了1行
- 写单测要花很多时间,甚至比写业务代码的时间还长,值吗?
- 业务代码经常变,之前写好的单测总不过,时间紧迫,只能先注释掉assert,牺牲单测质量
- 项目排期很紧张,在既要又要还要的情况下,只能不写单测,后期也没时间补
上面1,2,3,4归根结底是代码质量问题,既代码的可测试性不好,很难处置。5,6是项目管理问题,假设管理的质量意识到位,能给足研发停止单测的时间,是可以处置的。反之假设管理层面不愿意留出单测时间,那其实说明质量问题不是大问题。
常见处置办法
要体现单测的质量保证效果,需要从单测质量和数量两方面动手,那么如何提升单测的质量和数量?
常见的进步质量的做法就是培训,比如通过培训分享单测写的好的人的优秀经历。我就在公司内部给大家分享过几次单元测试100%覆盖技巧。
而要进步单测数量,除了研发自己写单测外,还有一种做法是将一部分单测开发工作移交给测试。但白盒测试一般都比较少,为了加大白盒测试人员的比例,也有通过培训黑盒测试成为白盒测试的做法。
当然相应的辅助管理手腕也是必要的,比如定期对单元测试代码停止抽查,对质量高的做惩办,对质量低的做提醒等等。
但其实我对通过测试人员处置单测问题是有所保留的。假设专业的程序员都不想写也写不好单测,测试人员就可以吗?
万万没想到我也要学编程
其实不论是单侧的质量还是数量,进步的关键都是代码的质量,特别是可测试性。不处置代码的可测试性,再怎么折腾都没啥用。
如何提升代码质量?去学习OOAD,设计形式,各种编程设计原则,层出不穷的方法论吗?扪心自问,我们真的学会并能灵敏运用这些知识,写出高质量代码吗?假设回答是的,我们今天干嘛还在讨论这个问题。这些手腕就其传授的知识而言自身没有问题,但这些手腕的效率很低,周期很长,无法短期见效。学会这些你能成为一个高手,但无论从管理还是本钱角度考虑,你能想象一个全是高手的团队吗。
既然做法都不是可以快速复制的工业化处置方案,我们必需另辟蹊径。从研发工程理论来讲,需要可以快速提升批量人员代码质量的手腕。
低代码处置方案
想要快速提升代码质量,实质上是如何低本钱产出高质量设计。只要这样才干处置代码可测试性差的问题,才有可能提升单测质量,此外还可以考虑如何减少必要代码量。进步单测数量的实质是希望覆盖更多的被测代码。假设能减少必要代码量,则单测工作量也会相应减少,同等人力投入下就可以覆盖更多的被测代码。
处置问题的办法在问题发生的层面往往是找不到的,要实现上面的目的,目光要超越代码层面。近年来兴起的低代码无代码技术就是一个可行的方案。但该技术争议也比较大,我认为主要原因是大多数低代码工具更倾向于低门槛使用者,而忽略了专业研发的使用场景,这篇文章中专门做了分析:低代码工具选项难题浅析。
X-Series是为后端研发打造的一套开源低代码框架,可以实现上面的目的。下面先简要介绍X-Series,再分析为什么X-Series可以低本钱产出高质量设计和减少必要代码量。
X-Series简介
X-Series 是面向后端研发人员的低代码工具,用于高效构建可理解,可维护的后台应用。它包含 3 个独立工具,分别对应流程处置,逻辑判断和状态管理。
xUnit利用流程图笼统后台流程处置。开发时根据需求对应的处置流程先创建流程图,这一般只花1分钟时间。流程图画好了,设计工作根本上也就完毕了。研发既可以拿着这个流程图去和需求方review,也可以用于和团队成员停止沟通,还可以在测试阶段协助白盒测试人员设计测试案例。
流程图设计完毕后,接下来的只需要为每个流程节点提供代码实现。不同的节点类型需要实现不同的预定义接口。一般常见的接口为以下4种:
- Processor:对传入参数停止处置,无返还结果
- Converter:对传入参数停止转换,返回一个结果
- Validator:对传入参数停止判断,返回true/false
- Locator:对传入参数停止判断,返回一个key
所有的传入参数类型均为Context类型。在系统中调用流程图也很方便。
xUnit非常注重使用体验,流程图的设计和代码的开发都可以在同一个IDE中完成。利用集成在 IDE 中的可视化编辑器,研发人员可以随时从节点跳转到代码,有了 xUnit 相当于有了一张系统蓝图,而不会迷失在代码海洋中。
xDecision 使用决策树模型来表达复杂逻辑判断。用户首先在模型中定义用于判断的变量和决策,需要的话还可以定义类型以方便和代码匹配。其次在图上添加节点,节点可以包含决策,也可以包含表达式用于进一步的判断。最后将节点连接起来并指定表达式,即可实现判断逻辑。
使用决策树仅需要创建模型实例并传入参数,不需要单独生成代码。对决策树的创建维护完全在模型中,假设事实变量和决策集合没有改变,则模型变卦时无需改动主程序。xDecision 还支持生成测试代码,用于快速检验模型的正确性。
xState 使用状态机模型来构建业务对象的状态模型,支持状态变化校验和事件处置调用。无论业务模型的状态有多复杂,都可以用状态图明晰的表达。同 xDecision 类似,假设事件和状态集合没有变化,修改模型后无需改变调用程序。
X-Series已经开源多年,在多个公司都有应用。其中xUnit和xState已经被我们公司多个研发部门采用,用户反响可以很显著的提升系统可理解性,进步组件复用性和研发效率。
提升可测试性的原理
在做进一步论述之前,我们先回忆一下什么是设计。所谓设计,实质上是一种系统分解的手腕,既如何将一个系统分解为一系列相关的更小的系统,持续这一分解的过程,直到到达可以直接编码实现的粒度。此粒度上的代码要能满足高内聚,低耦合的质量要求。
为什么说X-Series可以进步代码的可测试性?因为它可以同时满足低本钱产出高质量设计和减少必要代码量两个要求。
以xUnit为例,流程图是研发人员最熟悉的工具,人人都懂,利用流程图可以将系统以明晰的方式展示出来,并且将工作分解到节点级别。因为流程图是根底知识,不需要熟练掌握OOAD,设计形式或其他任何设计理念就可以使用,所以利用流程图就满足了低本钱的要求。假设流程图的每个节点假设还是比较笼统复杂,则可以通过子图的方式继续分解。这不但保证了设计手腕的一致性,而且由于不需要引入额外的设计手腕,也就防止了相关培训本钱。
流程图自身具备的明晰易懂的特性满足了高质量的要求。当流程图分解到节点的工作职责已经非常单一详细,可以利用代码直接实现时,则很容易满足代码的高内聚要求。在代码层面,xUnit预先定义了各类型节点要实现的接口。这些接口职责高度单一,研发人员只需要为接口提供实现即可。在减轻用户负担的同时还防止了设计引入缺陷。
流程图节点间的调度协调不需要单独代码实现,xUnit引擎会直接利用流程图模型自身来完成。假设说xUnit可以大幅减少粘合代码量的话,xDecision和xState则更进一步通过模型直接消灭了代码实现的必要性,因为它们生成的模型可以在应用中直接调用,不需要生成任何中间代码。
虽然使用X-Series可以低本钱产出高质量设计,大幅减少必要代码量,并从设计角度保证代码层面的高内聚。但作为一个完好的方法论我们还需要在代码层面为实现低耦合提供方案,否则还是无法彻底满足可测试性要求。
降低耦合度的技巧
在讨论技巧前我们先明确为什么低耦合是进步代码可测试性的关键?
例如 A 类的 a 方法依赖 B 类的 b 方法完成自身功能,b 方法可能是一次外部调用,一次数据库恳求,或者某种复杂运算。当A类和B类耦合度高的时候,例如A类在自己代码内部创建B类,则要为A类提供单元测试时,必需间接的满足B类的运行条件。这就是为什么耦合度高的代码可测试性差的原因。反之假设A类可以通过某种方式注入B类,则可以在单元测试时使用B类的mock来替代实际的B类完成对A类的测试工作。因为mock可以由我们提供,创建和使用过程都是受控的,因而耦合度低的代码可测试性就好。
由上面的例子可知,要降低耦合度,核心就是将所有外部依赖参数化。详细做法分两种情况:
- 假设B类实例在A类实例的生命周期内都不需要改变,那么只需将B类实例通过A类的构造函数注入。假设没有构造函数,可以创建一个包含B类实例的构造函数。
- 假设B类实例在A类实例的生命周期中会发生改变,那么只需要为A类创建一个B类实例的setter方法即可。
完成以上改造后,即可降低代码耦合度,因而针对 A 类 a 方法的单元测试的全部工作是:
- 把 B 类通过构造函数或 setter 从内部属性变为外部依赖
- 对 B 类做 mock,重载 b 方法使其能返回特定测试所需要的值
- 通过构造函数将 B 的 mock 注入到 A 类中
- 基于重载的 b 方法来实现 a 方法的单元测试
一个合格的单元测试应该要做到所有逻辑途径 100%覆盖,除非是特别简单的代码,例如规范的 getter/setter 外。有了完备的单元测试,我们就能快速检测被测代码自身行为是否符合预期,对系统其它部分是否形成影响,或者被其他部分的修改影响到。
结论
假设做一件事情特别费力,往往是方法不对。通过提升个人才干或运用强迫手腕进步单测质量效果并不好。而借助低代码,不但能低本钱产出高质量设计,还能大幅降低代码量,再结合提升可测试性的技巧,三管齐下就能有效进步单测覆盖率和质量。
作者简介
pure 50 cents,信也技术架构研究员,专注于中间件,低代码,运维平台等方面
来源:微信公众号:拍码场
出处:https://mp.weixin.qq.com/s/Jzpt4Cv5ffYsDCRP-4P5eQ |