跳到主要内容

Ch 6. 检查代码

本章主要描述静态白盒测试的优势、类型、技术,此外也将介绍有关编码规范和标准、如何从整体审查代码错误。

静态白盒测试:检查设计和代码

静态白盒测试是在不执行软件的条件下有条理地仔细审查软件设计、体系结构和代码,从而发现错误的一种测试方法。有时称为结构化分析

静态白盒测试是对动态黑盒测试的一种补充,以便在软件开发的早期阶段发现那些在黑盒测试难以发现或隔离的软件缺陷。

静态白盒测试能够为黑盒测试员提供那些容易产生缺陷的软件代码范围,从而更好地设计和应用测试用例。

正式审查

正式审查——也就是进行静态白盒测试的过程——通常包含四个基本要素:

  • 确定问题:审查的目的是找出软件的问题,而非指责参与者。
  • 遵守规则:要提前制定好一套适用于代码审查的规则,为审查提供一个框架。例如评审多少代码、从何种角度审查代码等。重要的是,让每个参与者知晓自己的责任。
  • 准备:每个参与者都需要为审查做准备,包括阅读代码、准备问题、准备解决方案等。
  • 撰写报告:审查结束后,需要撰写一份报告,记录审查过程中发现的问题和解决方案。报告应当尽快通知到相关人员,以供他们及时解决。

一旦正式审查的流程确定下来,就应该严格地按照既有的固定流程完成审查,否则可能会导致审查的效果不佳。

注意

要注意的是,不要以“为了写报告而写报告”的心态来进行审查。审查的目的是找出问题,而非为了写报告;报告本身的格式规定和要求也是为了更好的可读性。

千万别本末倒置。

审查的方式

  • 同事审查(或者伙伴审查):由团队内的其他成员进行非正式的审查。可以是开发者之间,也可以有测试员参与。
  • 走查(Walkthrough):编写代码的程序员向其他程序员和测试员组成的小组做正式陈述,审查队伍中应当尽可能包含一位高级程序员。通过汇报和提问-解答的方式发现代码中的缺陷,并在事后编写报告,描述问题并给出解决问题的计划。
  • 检验(Inspection):最正式的审查方式,要求每一个参与者都要提前准备好,审查的过程中要有一个记录员记录问题和解决方案。审查小组的成员按角色分工,从用户、测试员或产品支持人员的角度阅读代码,以发现问题。
    • 与前二者最大的区别在于做汇报的人非编写者,这迫使他阅读和学习代码,从而可能发现编写者忽略的问题。

编码标准与规范

标准是建立起来、经过修补和必须遵守的规则,而规范则是建议最佳做法。推荐更好的方式。

坚持符合标准和规范,有利于提高代码的可读性、可维护性和可靠性,同时也有助于提高代码的可移植性。

标准和规范的组成部分

标准或规范由以下四个部分组成:

  • 标题:标准或规范的名称。
  • 标准:描述标准或规范的内容,列出允许和不允许(或建议和不建议)的行为。
  • 解释说明:解释说明,阐述为什么这样做是好的编程习惯。
  • 例子:有一个例子会更好,可以帮助开发者理解标准和规范。当然这不是必须的
信息

在代码审查中,需要注意区分标准、规范问题风格问题。尽管二者都是值得讨论的软件问题,但必须注意后者作为一类主观问题,不是软件缺陷

这就像是静态分析器(Linter)和格式化工具(Formatter)的区别一样,前者是为了检查代码中的错误,后者是为了统一代码风格。二者的核心区别在于,格式化或修改代码风格并不会导致软件的行为发生变化,而不遵循标准或规范则可能意外地影响软件的行为。

格式化侧重于提高代码的可读性和可维护性,而标准和规范则侧重于提高代码的可靠性(避免出错)。

通用代码审查清单

以下累出一些常见的在静态白盒测试期间需要注意的问题,可以作为一个通用的代码审查清单:

数据引用错误

使用未经正确声明和初始化的变量、常量、数组等数据结构导致的软件缺陷。

  • 是否引用了未初始化的变量?
  • 下标是否在合法域内(是否是整数、是否越界、是否是负数……)?
  • 是否存在在迭代过程中擦除迭代器的行为?这是否会导致访问非预期的数据?
  • 哪些地方可以使用常量代替变量?
  • 是否将非预期的值赋值给了某类型的变量?
    • 在动态类型语言中尤其需要注意。
  • 指针是否指向了正确的内存区域?存在野指针吗?
  • 同一标识符是否对应不同的数据或类型?是否存在命名空间污染?
  • 同名变量的作用域是否清晰?是否存在变量遮蔽?
  • ……

数据声明错误

不正确地声明或使用变量和常量导致的软件缺陷。

  • 变量是否赋予其预期的类型?
  • 变量是否在声明时完成了初始化?初始化值是否合法?
  • 存在未使用的变量吗?
  • 没有显式声明的变量的定义在何处?
  • ……

计算错误

由于错误的计算语句导致的软件缺陷。

  • 计算过程中是否存在隐式类型转换导致的精度丢失?
  • 是否存在除零错误?
  • 是否存在溢出或下溢错误?
  • 赋值时是否可能产生类型转换导致的精度丢失?
  • 变量的值是否满足其定义域?
  • 变量的求值顺序是否符合预期?运算符优先级是否正确?有必要添加括号以明确优先级吗?
  • ……

比较错误

判断条件中的比较错误导致的软件缺陷。

  • 是否要考虑相等的情况?
  • 相等性判断是否使用了正确的比较运算符?
    • 是否使用了 == 而不是 =
    • 判断的对象是指针、引用还是值?
    • 是否存在类型转换导致的比较错误?
  • 逻辑计算中操作数是布尔值吗?
  • ……

控制流程错误

由于错误的控制流程导致的软件缺陷。

  • 语句块的开始与结尾({}beginend)是否匹配?
  • 是否存在死循环?
  • 是否存在不可达的死代码?
  • 是否处理了非预期的情况(例如 switch-case 中的 default)?
  • 是否存在缺少的 break (例如 switch-case 中)?
  • 循环的每个循环变量的含义和范围清晰吗?
  • ……

函数调用错误

由于错误的传递参数或返回值导致的软件缺陷。

  • 函数调用的参数是否与函数声明中的一致?次序和类型是否正确?
  • 支持重载的语言中,实际调用的函数是否是预期的函数?
  • 传递引用和指针时,是否意外修改对应的值?
  • 是否有传值带来的拷贝开销?存在优化空间吗?
  • 变量的值是否与其实际含义不相符(例如单位不匹配)?
  • ……

输入输出错误

与文件系统或外部设备交互时的软件缺陷。

  • 输入输出时的数据格式是否正确?
  • 文件操作时,打开模式是否正确?
  • 是否处理了相关的错误(例如文件打开失败或文件不存在的情况)?
  • 文件的编码是否正确?
  • ……

其他问题

其他可能导致软件缺陷的杂项问题。

  • 软件是否有移植到其他平台的可能性?是否存在平台相关的代码?有必要进行抽象吗?
  • 软件是否使用了来自第三方的库?是否存在版本不兼容的问题?第三方库使用的许可证是否与软件兼容?
  • 是否考虑了对低性能机器、不同架构 CPU 等的兼容性?是否依赖于特定硬件?
  • 软件是否需要加入外语支持?所有的字符串是硬编码在源代码中,还是放入了资源文件中?
  • 编译时是否开启了警告?是否存在警告信息?
  • ……

小测验

问题摘录与参考回答

判断是非:静态白盒测试可以找出遗漏之处和问题。

答:

是。遗漏的地方通常比已经存在的问题更难发现。

如果要求程序员在命名变量时只能使用 8 个字符并首字母必须采用大写的形式,那么这是标准还是规范呢?

答:

必须指出了强制性,所以这是标准