OverRainbow

Testing Principles of software development

☕️ 1 min read

你可以从本文了解到

本文是对《软件设计的 201 个原则》的第6章——软件开发的测试原则的学习

测试是包含以下行为的集合:

  1. 对独立的软件组件执行测试(即:单元测试,Unit Testing),以确保其行为与组件设计规格说明中的定义足够的接近

  2. 对执行过单元测试的组件集合执行测试(即:集成测试,Integration Testing),以确保这些组件一起工作时的行为足够接近设计中的说明。

  3. 对集成测试过的所有组件进行测试(即:软件系统级测试,Software Systems-level Testing),以确保它们可以作为一个系统来运行,且行为足够接近软件需求规格说明中的定义。

  4. 制定软件系统级测试的测试计划。

  5. 制定软件集成测试的测试计划。

  6. 制定单元测试的测试计划。

  7. 建立测试装置(test harness)和测试环境(test environment)。

107 依据需求跟踪测试

理解哪些测试可以验证哪些需求是很重要的。有如下两个原因:(1)在生成测试时,你会发现,了解是否所有需求都在被测试是很有用的。(2)在执行测试时,你会发现,了解正在验证哪些需求是很有用的。

此外,如果你的需求已经排了优先级(原则 50),可以很容易得出测试的相对优先级;也就是说,一个测试的优先级是其所有对应需求的优先级的最大值。

维护一个大二进制表,其中行对应于所有软件测试,列对应于软件需求规格说明中的每个需求。任何位置的 1 表示此测试有助于验证此需求。

注意,一整行都没有被置 1 表示此测试没有目的,一整列都没有被置 1 表示该需求漏测。能够成功地创建这样一个表,取决于你唯一地引用每个需求的能力(原则 52)。

108 在测试之前早做测试计划

109 不要测试自己开发的软件

软件开发人员永远不应成为自己软件的主要测试者。开发人员比较适合进行初始调试(译者注:自测)和单元测试。 [相反的观点,可参见Mills, H., et al., "Cleanroom Software Engineering",in IEEE Software, 4, 5 (September 1987), pp. 19–25.]

PS,目前确实有新的倾向,由程序员来测试自己的代码。但本原则提到的因素依然值得考虑。一个能够充分对自己代码进行测试的程序员,需要能够把自己的视角切换到一个测试人员,并且有发现bug的足够欲望。

110 不要为自己的软件做测试计划

你不仅不应该测试自己的软件(原则 109),而且也不应该负责为软件生成测试数据、测试方案或测试计划。如果你负责了,那么你可能会在测试生成中犯与软件创建中相同的错误。例如,如果你在设计软件时对合法输入的范围做了一个错误的假设,那么在生成测试计划时,你很可能会做出同样的假设。

111 测试只能揭示缺陷的存在

无论多么彻底和深入,测试只能揭示程序中缺陷的存在,而并不能确保程序没有缺陷。它可以增加你对程序正确性的信心,但它不能证明程序的正确性。为了获得真正的正确性,必须使用完全不同的方法,即正确性证明。

112 虽然大量的错误可证明毫无价值,但是零错误并不能说明软件的价值

这是杰拉尔德·温伯格(Gerald Weinberg)的“无差错谬论”(Absence of Errors Fallacy)。它真正地将测试纳入了视野。它还将所有的软件工程和管理纳入视野。本原则的第一部分显然是正确的,有很多错误的软件是没用的。第二部分则发人深省。它表达的是:无论你多么努力地消除错误,除非你在开发正确的系统,否则你都是在浪费时间。

Akao 的《质量功能部署》(Quality Function Deployment, Cambridge, Mass.: Productivity Press, 1990)详细介绍了一种方法,用于确保你在整个软件生命周期中开发正确的系统。本原则的一个推论是,如果你在开发错误的系统,那么世界上所有的形式化方法、所有的测试和所有的产品保证都将于事无补。

113 成功的测试应发现错误

114 半数的错误出现在 15% 的模块中

保守估算,在大型系统中,大约所有软件错误的半数出现在 15% 的模块中,80% 的软件错误出现在 50% 的模块中。Gary Okimoto 和 Gerald Weinberg 的结论更引人注目,所有错误的 80% 是在仅仅 2% 的模块中发现的(参见 Weinberg 的《质量软件管理》: Quality Software Managetnent, Vol. 1: Systems Thinking, New York: Dorset House, 1992)。因此,在测试软件时,你可以这样认为,在发现错误的地方,很可能会发现更多错误。

要维护日志(译者注:指测试日志),不仅记录在项目的每个时间段内发现了多少错误,还要记录每个模块发现了多少错误。当历史表明一个模块非常容易出错时,你最好从头开始重写它,强调简单性(原则67),而不是聪明。

115 使用黑盒测试和白盒测试

116 测试用例应包含期望的结果

117 测试不正确的输入

118 压力测试必不可少

119 大爆炸理论不适用

你不能通过忽略单元测试和集成测试来节省时间。

120 使用 McCabe 复杂度指标

121 使用有效的测试完成度标准

有效度量测试进度的两个想法是:

  • 每周发现新错误的比率。

  • 暗中在软件中埋下已知的 bug ( Tom Gilb 管这个叫 bebugging )后,这些 bug 到目前为止被发现的百分比。

对于测试进度的一个无效指标是测试用例通过的百分比(当然除非你确定测试用例很好地覆盖了需求)。

122 达成有效的测试覆盖

在测试计划生成或测试执行阶段,有一些指标可以用来确定代码执行测试的全面程度。

  1. 行覆盖率,用于衡量至少执行一次的语句的百分比。

  2. 分支覆盖率,用于衡量程序中被执行的分支的百分比。

  3. 路径覆盖率,用于衡量所有可能路径(通常是无限的)覆盖程度

123 不要在单元测试之前集成

124 测量你的软件

一个发现原因的方法是测量你的软件,也就是,嵌入特殊的指令到软件中,来报告执行轨迹、异常状况、过程调用等等

125 分析错误的原因

错误在软件中是很常见的。我们会花费大量的资源来发现和修复它们。

从一开始就防止它们的发生,从而降低它们的影响,是更划算的。

为此的一个方法是,当检测到错误的时候,分析它们的原因。

126 对“错”不对人

当你或他人在你的代码中发现错误时,公开坦诚得讨论它。与其责骂自己,不如将它当作自己和他人的学习经历(更多信息见原则 125)。