三、单元测试要测试的是什么? The Right-BICP

编写单元测试的用例是验证代码的正确性,很多情况下,我们倾向于让测试沿着主路径,也就是”happy path"前进,仅能验证代码的功能,却无法保证代码的健壮,因此本文就将解决单元测试测试什么这个问题。
在《Pragmatic Unit Testing in Java 8 with JUNIT》这本书中,采用了RIGHT-BICEP(一种训练二头肌的器械)这个助记符来帮助记忆编写单元测试的要点。
Right Are the result right?
B       Are all the boundary conditions correct? 边界条件都正确吗?
I         Can you check inverse relationships? 是否检查反向关系?
C       Can you cross-check results using other means?  是否进行了交叉检查?
E        Can you force error conditions to happen? 是否检查了异常情况?
ßP        Are performance characteristics within bounds? 性能是否在设计范围内?

[Right]-BICEP 结果都是正确的吗

  • 测试最重要的目的是确认代码产生了预期的结果
  • RIGHT这个词首先反应了单元测试最重要的点,也即“正确性”
  • TDD是一种好的实践方式,它要求我们首先在理解业务的基础上编写单元测试
  • 有些时候需求未确定,但测试仍然可以进行,变更不可避免,要学着去适应

Right-[B]ICEP:Boundary Conditions 边界条件

编写单元测试用例时需要考虑边界条件,如:
  • 不合常理的名称,如"!*W:X\&Gi/w$→>$g/h#WQ@
  • 格式不正确的数据,如缺少了顶级域名的邮箱地址:fred@foobar
  • 可能导致溢出边界条件
  • 空值,null值或者0值
  • 超出合理范围的输入条件,如150岁的人
  • 在本不应重复的记录中出现了重复的记录
  • 应该排序的输入未排序
  • 本应该按照时间顺序发生的未按照时间顺序发生
另外需要注意:以上是常见的边界条件,在编写单元测试用例时可以参考。需要注意的一点是,单元测试到什么程度是由编写者来决定的,例如团队内的单元测试与向外暴露的单元测试的覆盖可能不同,对外提供的接口,由于输入参数不可信程度更高,因此需要更加全面的测试覆盖。

边界条件助记符 CORRECT

  • Conformance  一致性,输入与期待的格式一致吗?
  • Ordering 一组输排序和不排序有影响吗?
  • Range 输入是否在合理的范围内?
  • Reference 代码是否依赖了任何外部资源,而这外部资源不受控?
  • Existence 输入存在吗?非空,非零...
  • Cardinality 基数,是否提供了足够的输入
  • Time (绝对和相对的)事情都是按照顺序发生的吗?是否在合适的时间,以及及时发生?

Right-B[I]CEP: Checking Inverse Relationships 检查反向关系

从反向关系验证意味着找寻一条与现有逻辑不通的方案进行验证,如验证插入语句时通过查询语句验证。

Right-BI[C]EP:Cross-Checking Using Other Means 交叉检验

可以通过针对目标的不同实现方式来进行检验,这种检验被称为交叉检验,如不同的算法。

Right-BIC[E]P: Forcing Error Conditions 引发错误的条件

好的单元测试不是那种简单的覆盖明显的逻辑路径的,而是要详尽考虑不同的异常情况,对代码的逻辑提供有效保护。
异常情况也是单元测试需要考虑的内容,下面是常见的一些需要考虑的状况。
  • 内存不够
  • 磁盘空间不够
  • 挂钟时间问题
  • 网络可用性以及错误
  • 系统负载
  • 受限的调色板?
  • 非常高或者非常低的视频清晰度

Right-BICE[P]: Performance Characteristics 性能特性

过早优化是万恶之源的出处:
Rob Pike of Google: “Bottlenecks occur in surprising places, so don’t try to second guess and put in a speed hack until you have proven that’s where the bottleneck is.”
  • 可以通过设计单元测试帮助查找性能问题所在
  • 对于测试性能的单元测试,因测试的执行时间依赖于环境,因此除了在同一环境运行外,没有太大的比较意义
  • 更常用的场景是提供了一个优化基线,通过单元测试能够不断看出优化效果(实际就是一段驱动代码)
  • 如果性能是产品的关键考量,应该从更高层次考虑(JMETER),而非采用单元测试
  • JUnitPerf可以提供单元测试级别的性能测试能力
posted @ 2020-10-19 17:34  纪玉奇  阅读(308)  评论(0编辑  收藏  举报