二、优秀单元测试的五个特征FIRST

单元测试常见问题

  • 单元测试对接手人没有意义
  • 测试会间断性的失败
  • ”测试“并没有实际意义
  • 测试需要过长的时间执行
  • 测试没有有效覆盖代码
  • 测试与实现耦合太紧密,意味着一点点调整将会导致大量测试失败
  • 测试太复杂,需要预制太多条件

好的单元测试所要遵循的几个原则

  • [F]AST 快速性
  • [I]solate 隔离性
  • [R]epeatabel 可重复性
  • [S]elf-Validating 自验证性
  • [T]imely 及时性

[F]IRST: Fast! 快速!

  • 毫秒级的单元测试才是合格的单元测试
  • 单元测试的首要原则是快速,只有以毫秒级别就能得到运行结果的单元测试才能使开发人员频繁去运行它,而只运行修改部分的单元测试是不可行的(无法保证影响范围),而将需求批量完成之后运行则会增加合入的难度。
  • 单元测试的价值在于其可以针对系统提供持续的,有一定复杂度的并且是快速的反馈。
  • 一种编写快速单元测试的方案是重新组织代码,将依赖于外部低速接口的逻辑单独抽离出来,其他方法均依赖内存数据结构,这样单元测试的编写相对简单,且对于依赖外部低速接口的方法,可以采用Mock的方式进行测试,保证接口的快速特性。
  • 如果一个单元测试需要依赖数据库,那这个单元测试是低效的

F[I]RST: Isolate your tests 隔离你的测试

  • 隔离性指的两个方面
    • 不要依赖外部数据源等低速的,可能被共享的资源
    • 单元测试彼此独立,可单独执行,不依赖测试套中单元测试的执行顺序
    • 每个单元测试仅关注逻辑的一个方面,有利于排错
  • 好的单元测试专注于要测试的一小块代码,也就是我们所说的“单元”,测试与越多代码打交道,越容易偏离
  • 不要依赖外部存储,因其他人可能也正在使用,导致单元测试执行结果不可控
  • 单元测试不要依赖于其他单元测试,即时是同一个测试套,即时仔细调整了顺序,还是有可能因为依赖链的问题失败,因此测试间也要彼此隔离。
  • 在任何时间以任何顺序执行任何一个测试都不会失败
  • 一个单元测试应该关注与逻辑的一个方面,如果要在某个单元测试中加入断言,需要考虑一个,这个断言真的是我需要的吗?如果确实描述了某个场景,那是否要将该断言抽取为一个测试方法呢?
  • 测试用例的单一职责反过来会要求类/方法的单一职责(SRP),这也同时反向驱动了类/方法的完善

FI[R]ST: Good Tests Should Be [R]epeatable 理想的单元测试需要是可重复的

  • 可重复测试意味着每次运行得到同样的结果,也即不能依赖于任何外部不可控的因素
  • 使用mock对象避免依赖不可控因素,如当前时间也是不可控因素,因其会发生变化
  • 单元测试需要保持运行稳定,如果间歇性的失败,会导致我们不断的去查看这个测试,不可靠的测试也就失去了意义

FIR[S]T: [S]elf-Validating 自验证

  • 单元测试需要采用Asset语句等进行自验证,也即当单元测试执行完毕之后就能得知测试情况,全程无需人工接入
    • 人工接入效率低
    • 人工接入不可靠
  • 自验证的测试用例可以引入持续集成(CI)提供质量保障

FIRS[T]: [T]imely 及时性

  • 如果等代码稳定运行再来补齐单元测试可能是低效的
  • 最有效的方式是在代码写完之后立即进行单元测试,或者最好采用测试驱动开发模式
  • 单元测试最好形成习惯,团队内部如果能够认识到单元测试的重要性,可以采用一些手段来保证,如
    • 代码检查
    • 未进行单元测试的代码不允许提交
  • 如果编写单元测试成为习惯,那很大可能会倒逼代码编写时考虑易测试性,从而间接提高代码质量
posted @ 2020-10-19 17:31  纪玉奇  阅读(1679)  评论(0编辑  收藏  举报