谷歌的软件工程 读书笔记(十二)单元测试


谷歌的软件工程 读书笔记(十二)单元测试文章插图
除了防止bug发生 , 单元测试的一个重要收益是提升开发效率 。

  • 单元测试一般体量很小 , 这就意味着它可以快速运行 , 快速获得反馈 , 也比较稳定 。
  • 一般可以和写代码的时候一起写 , 不需要考虑更大范围的问题
  • 提高代码覆盖率 , 让工程师对自己的修改更有信心
  • 单元测试出错的时候很容易定位和理解问题
  • 单元测试可以作为例子和文档
因为单元测试占据了开发者大量的时间 , 谷歌花费很大的力气增加单元测试的可维护性 。
有的时候 , 当你增加了一些功能后 , 你会发现很多单元测试都失败了 , 有两种可能 ,
  1. 你的测试比较脆弱 , 容易失败
  2. 你的测试不够清晰 , 很难定位出了什么问题
防止脆弱的测试脆弱的测试指的是 , 当实际并没有出错的情况下 , 你的测试会失败 。 如果你每次新加功能 , 你都需要修改你已经存在的单元测试 , 那么很难称你的测试是自动化的 。
谷歌有一些最佳实践和模式来使得单元测试更加稳固 。
理想情况下 , 当系统需求没有发生变化的时候 , 一旦测试写好了 , 我们希望它永远不会发生变化 。
【谷歌的软件工程 读书笔记(十二)单元测试】对于以下四种类型的变化:
  1. 单纯的重构
  2. 新特性和功能
  3. 修Bug
  4. 系统的行为更改
除了第四种 , 因为系统的行为有更改 , 我们需要修改已有的单元测试 , 其它三种情况 , 已有的测试是不应该被修改的 。
对于系统的测试应该和用户的使用方式保持一致 , 所以测试应该是基于公开的API的 。
定义单元的一些规则:
  • 如果一个方法或者类只是为了支持其它类或者函数 , 他不应该被看作是一个单元
  • 如果一个包或者类被设计可以有任何人直接访问 , 他应该被看作一个单于
  • 如果一个包或者类被设计成只有它的所有者可以访问 , 但是它提供的是一般的通用功能 , 他应该被看作一个单元
测试公共API要优于测试实现细节 。
测试状态而非交互
基于交互的测试更脆弱
编写清晰的测试即使我们完全消灭脆弱的测试 , 测试总有一天会失败 。 测试失败提供非常有意义的信号 , 这是单元测试的主要价值之一 。
测试失败有两种原因:
  • 系统有问题 , 有bug , 这个是我们单元测试的主要功能
  • 测试本身有问题 。
清晰的测试可以很容易判定是bug还是测试本身的问题 。
测试的清晰性非常重要 , 因为测试代码往往比维护它的工程师活得更久 , 这倒不是因为程序员都短命 , 他们往往会经历离职 , 升职或者转到别的项目 ,而不再维护这些测试代码 。 这个时候往往没有人能搞明白这些测试代码究竟在搞什么 。
使测试简洁并完整
测试应该完整 , 它应该包含所有理解该测试需要的信息
测试应该简洁 , 他不应该包含任何额外的信息
测试行为而为方法
有的工程师喜欢根据编码的内容来写测试 , 随着内容的增加和变复杂 , 测试的代码也随之增长 。 测试应该关注行为 。 使用行为来为你的测试命名 。
不要在测试代码中引入逻辑
清晰的测试代码看上去非常简单 , 如果你的测试拥有复杂的逻辑 , 你是不是有需求来写一些代码来测试你的测试代码?
编写清晰的错误信息
好的错误信息和测试的名字一样 , 简单清晰 。
测试和代码共享生产代码应该遵守DRY规则 , 就是不要重复你自己 。
而测试代码需要遵守DAMP规则 , 提供描述性和有意义的短语 。
  • 共享值 account_2不是一个好名字 , 使用一个描述性的名字更好 , 例如closed_account
  • 共享设置
  • 定义测试的基础设施
总结
  • 争取让你的单元测试稳定
  • 基于公共API来进行测试
  • 测试状态而非交互
  • 保持你的测试简洁并完整
  • 测试行为而非方法
  • 用测试的行为来命名测试
  • 不要在测试中包含逻辑
  • 提供清晰的错误信息
  • 共享测试代码的时候遵循DAMP比DRY更重要