一个完整的单元测试实践(下)

发表于:2024-1-25 09:49

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:佚名    来源:稀土掘金

  为什么要写单元测试
  错误恒定定律
  程序员的错误产出比是个常数
  对某一个程序员来说,实现相同功能会犯的错误(BUG)是固定的,不受程序员自身意愿影响,不受绩效影响,也不受项目紧急程度影响。不考虑程序员水平的成长,错误产出比在很长一段时间(每个项目的间隔)内可以认为是个常数。
  场景
  1. 感觉状态很好,多写了一倍代码感觉bug数肯定比昨天还少。
  2. 开会时要求程序员尽量不要写bug。
  规模代价平方定律
  为了减少错误修复的成本,要尽可能早的发现错误,在尽量小的范围内定位并修复错误。由于这是一个平方律而非线性率,所有这方面的努力都是非常划算的。
  目的
  错误率恒定律告诉我们错误是不可避免的,而规模代价平方律告诉我们要尽早发现错误。
  单元测试的目的是尽早在尽量小的范围内暴露错误
  好处
  1. 验证代码的正确性,保证新增、修改、重构后的正确性;
  2. 写出可测性、可维护性较高的代码,提升代码质量;
  3. 单测有利于我们更早的发现问题,在整个问题排查过程中是ROI最高的;
  4. 可以加深对业务的理解。
  认知误区
  补单测
  早会、周会上经常听到"XXX功能已经写完了,今天的工作是补些单测,或者单测覆盖率不达标,需要补单测",甚至我自己都这么说,这样是不对的,亲身体验:自己给自己补单测都觉得费劲,让别人来补更加费劲。
  单测 应该随着代码同时产生,而不应该是补出来的。
  why
  1. 错误恒定定律;
  2. 人性问题。
  项目紧,没时间写单测
  这也是我们经常说的话,尤其是没有写单测习惯的时候经常会说的话。
  不考虑单测框架自身的学习成本,任何情况下写单测都只会降低整体交付时间。
  Why
  1. 错误率恒定定律。
  2. 规模代价平方定律。
  错误率恒定,需要的调试量也是固定的,如果说项目紧不写单测,看起来编码阶段省了一些时间,但必然会在测试和线上花掉成倍甚至更多的时间来修复。
  基本指导原则
  【原则】AIR原则:
  A: Automatic(自动化)
  ·单元测试应该是全自动执行的,并且非交互式的。结果需要「断言」自动判断对错。
  · 测试用例通常是需要和 CICD 集成的,执行过程必须完全自动化才有意义。
  I: Independent(独立性)
  单测之间是独立无耦合的,单测是可以独立运行的,无外部依赖
  R: Repeatable(可重复)
  不修改实现逻辑情况下,重复执行的结果应该一致单元测试是可以重复执行的,不能受到外界环境的影响。
  【原则】 BCDE 原则:
  · B: Boder 边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
  · C: Correct 正确的输入,并得到预期的结果。
  · D: Design 与设计文档相结合,来编写单元测试。
  · E: Error 强制输入错误数据(如:非法数据、异常流程、非业务允许输入等),并得到预期结果。
  如何火力全开
  代码复杂度四象限
  1. 领域复杂度,代码的领域复杂度越高,里面的业务逻辑就越多。
  2. 对外依赖度,依赖度越高,说明代码和外部的 Class 交互点多。
  分为四个象限:
  1. 业务复杂、依赖又少,是业务逻辑集中的代码。比如业务算法。
  2. 业务简单、依赖又少,是一些简单代码,比如构造函数,数据对象等。
  3. 业务复杂、依赖多,是复杂度高的代码,测试起来也会比较困难。
  4. 业务简单、依赖多,是管理依赖的代码。比如消息总线。
  再看规模代价平方定律
  拆分详细 ,防止笛卡尔集 存在,提升复杂度,无法mock。
  再看好处
  编写代码时经过重构,依赖管理和业务逻辑、逻辑清晰、易测、易维护、易看懂。
  再看定义
  最小可测单元: 只专注一件事: 依赖管理、业务、算法。
  单测阶段
  什么场景下适合单测
  FURPS 模型
  FURPS 模型来解释一下需求,FURPS 是用 5 个维度来描述一个软件的功能需求,
  ·F=Function 功能
  · U=Usability 易用性
  · R=Reliability 可靠性 ps:可用性、准确性和可恢复性等方面——例如,计算或 系统从关闭故障中恢复的能力。
  · P=Performance 性能
  · S=Supportability 可支持性 ps:可测试性、适应性、可维护性、兼容性、可配置性、可安装性、可扩展性、可本地化性
  测试覆盖率真的有效么
  代码覆盖率
  简单来说,代码覆盖率是指,至少被执行了一次的条目数占整个条目数的百分比。
  行覆盖率又称为语句覆盖率,指已经被执行到的语句占总可执行语句(不包含类似 C++ 的头文件声明、代码注释、空行等等)的百分比。这是最常用也是要求最低的覆盖率指标。实际项目中通常会结合判定覆盖率或者条件覆盖率一起使用。
  代码覆盖率的局限性
  举个极端的例子,如果一个被测函数里面只有一行代码,只要这个函数被调用过了,那么衡量这一行代码质量的所有覆盖率指标都会是 100%,但是这个函数是否真正实现了应该需要实现的功能呢?
  代码覆盖率 的计算是基于现有代码的,并不能发现那些“未考虑某些输入”以及“未处理某些情况”形成的缺陷。
  如何度量单元测试的质量
  变异测试覆盖率
  每一次代码迭代,就是一次变异。
  命令
  执行结果
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.0" with checksum b705f4c99e6d572de509609eb0a625be
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.1" with checksum eb54efffc5edfc7eba2b276371b29836
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.2" with checksum 011df9567e5fee9bf75cbe5d5dc1c81f
  --- /home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go+++ /tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.3@@ -16,7 +16,7 @@
          }
          if n < 0 {
  -               n = 0+
          }
          n++
  FAIL "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.3" with checksum 82fc14acf7b561598bfce25bf3a162a2
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.4" with checksum 5720f1bf404abea121feb5a50caf672c
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.5" with checksum d6c1b5e25241453128f9f3bf1b9e7741
  --- /home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go+++ /tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.6@@ -24,7 +24,6 @@
          n += bar()
          bar()
  -       bar()
          return n
   }
  FAIL "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.6" with checksum 5b1ca0cfedd786d9df136a0e042df23a
  PASS "/tmp/go-mutesting-422402775//home/zimmski/go/src/github.com/zimmski/go-mutesting/example/example.go.8" with checksum 6928f4458787c7042c8b4505888300a6
  The mutation score is 0.750000 (6 passed, 2 failed, 0 skipped, total is 8)
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号