跳到主要内容

Ch 3. 软件测试的实质

本章从软件和实际的角度尝试解释软件测试的实质,理解为什么软件永远不会完美、必须学会取舍,从而了解软件测试的作用、影响和责任。

测试的原则

完全测试程序是不可能的

由于无法穷举所有可能的输入值输出结果执行路径,所有的测试都是有限的不完全测试

此外,对软件说明书的理解这类主观因素的存在,也使得测试不可能完全。

软件测试是有风险的行为

根据上条原则,在实际的软件测试中必然选择不去测试所有的情况,这就引入了风险

提示

软件测试员必须学会的一个关键思想是:如何把数量巨大的可能测试减少到可以控制的范围,以及如何针对风险做出明智的抉择。换言之,哪些测试重要,哪些不重要

测试无法显示潜伏的软件缺陷

测试只能证明软件中存在缺陷,但不能证明软件中不存在缺陷。仍然是第一条原则所述的那样,任何情况下都不可能保证软件是完全没有缺陷的。

唯一的方法是继续测试,也许还能找到一些。

找到的缺陷越多,说明实际上缺陷更多

这条可能读起来让人摸不着头脑,但实际上想想就会发现是显而易见的。

软件缺陷就像它的名字(Bug)一样,当你在家中发现一两只臭虫时,你就会意识到家中可能有更多的臭虫。根据第一条第三条原则,这条原则是符合逻辑的。它指出了缺陷之间的相关性

一般而言,我们有如下事实:

  • 程序员也会有心情不好的时候。 这是自然,人无完人,程序员也不例外。当程序员心情不好时,他们的工作效率会降低,这就意味着他们可能会犯更多的错误。一个软件缺陷表明很可能附近还有更多的缺陷。
  • 程序员往往犯相同的错误。 每个人都有习惯,人们总是常常落入自己曾经受困的陷阱;此外,对于背景类似、技能水平类似的程序员,他们之间也会共享一些相同的错误。
备注

闭上眼睛,想想你在写第一个 C 语言程序的时候。忘加分号,写出 mian 函数……这些你曾经犯过的错误,你的同学、你的朋友,他们也曾经犯过。

——这就是人类的共性。

[德] 格奥尔格·威廉·弗里德里希·黑格尔

历史给我们的教训是,人们从来都不知道汲取历史的教训。

  • 某些软件缺陷实乃冰山一角。 当某些基础性的组件或设计出现问题时,它们会随之影响整个软件系统。这就是为什么有时候一个小小的缺陷会引发一连串的问题。

杀虫剂怪事

这是一条有关软件测试的有趣的原则。它指出了软件测试的非线性特性。

就像自然选择为臭虫提供了抗药性一样,软件测试也会为软件缺陷提供某种无形的“免疫力”。总是使用同一种测试手段,软件缺陷就会表现出——注意,是表现,这里不存在实质上的因果关系——抵抗力。

注意

和人们对抗药性和自然选择的误解一样,并非测试行为本身会使软件缺陷变得更难被发现,而是软件缺陷本身的性质使得它们更难被发现。只不过,测试这一选择性行为筛去了那些容易被发现的缺陷,留下了那些难以被发现的缺陷。

这条原则要求测试员们不断采取新的测试手段,对程序的不同部分进行测试。

并非所有缺陷最后都要修复

不同测试的目的是项目小组和软件测试员决定的。有时候,一个缺陷可能被认为是不重要的,或者是不值得修复的。

一般来说,我们有这些原因:

  • 成本问题:无论是时间还是金钱,修复缺陷都是有成本的。有的时候,现实情况不允许我们付出这么多成本。同时,修复缺陷的成本也许远远超过了缺陷本身的影响。
  • 修复的风险太大:软件本身是脆弱的,修改软件可能冒很大的风险:修复一个缺陷可能引发更多的缺陷。这就是所谓的遗留代码
  • 不算真正的软件缺陷:这是一个有趣的原因。就像游戏社区中常常调侃的那样,“这不是 bug,是 feature”。有时候,软件缺陷可能是某种刻意的不完美设计,或者它无意间能够负负得正、产生意想不到的好效果。
  • 不值得修复:这和第一条有些相似。有的时候我们必须权衡,也许某个错误在某个特定情况下才会出现,而这个情况(也就是前置条件)又是极少发生的。这时候,我们可能会选择不修复这个缺陷。
记住

这条原则并不是作为测试员的你做出错误决策免死金牌

不值得修复为例,这实际上是非常主观的。当你或开发小组认为这个缺陷不值得修复时,有可能你正在为未来埋下巨大的隐患。不幸的是,和人生中的许多选择一样,只有时间才能证明你的选择是否正确。

什么时候才叫缺陷难以说清

这条原则指出了软件缺陷的主观性

本书中严格遵循第一章中给出的软件缺陷五大原因。这种情况下,我们的一个推论是:只有被看见的缺陷才能真正算作缺陷;而尚未发现或未观察到的缺陷只能说是潜在缺陷。

备注

这个问题也许永远都没有答案——想想那个老问题:

森林里的一棵树倒下,但无人听见,它是否发出声音?

在软件测试的实践里,我们不必纠结于唯物主义和唯心主义的哲学思辨,去和同行聊聊,或许能找到一些启示。

产品说明书永远没有最终版本

这条原则指出了软件开发的动态性。就像之前所说,计划永远赶不上变化。如果软件开发墨守成规,坚持不引入变更,那么终将被市场淘汰。

作为测试员,我们必须意识到,产品说明书的变更是不可避免的。未经测试的功能会增加,经过测试的功能也可能被修改或删除。

软件测试员的工作并不讨喜

软件测试员——哈哈,就像任何系统中的监察员一样——总是被人讨厌。在别人的工作中找出问题和挑刺是他们的本职工作,因此保持和睦的为人处世之道同样重要。

  • 早点找出问题:不要在你的同事已经将近完成他的工作时才告诉他某些基础性的地方出了问题——控制风险和错误的影响,这就是你的工作,这也能让人心理上更容易接受。
  • 控制情绪:软件测试员的工作是找出问题,而不是制造问题。不要因为找到了一个缺陷而沾沾自喜,也不要因为找到了一个缺陷而责怪他人。软件测试员的工作是为了提高软件质量,而不是为了找茬。
  • 不要总是报告坏消息:多和你的同事交流和合作:工作是工作,生活是生活。尽量避免自己只给同事留下“瘟神”的印象。

软件测试是一个讲究条理的技术职业

这条原则没有什么特殊的。它只是告诉你,现在软件测试是一种正规的职业选择了——而且需要训练和规范,具有发展前景。

测试的术语和定义

精确(precision)和准确(accuracy)

精确描述了测试结果之间的差异较小,而准确描述了测试结果与实际情况较为接近。

示例

拿打靶来举例,进行几次射击总会是以下几种结果:

  • 既不准确也不精确看起来你没怎么摸过枪! 你的子弹不仅打在了靶子的四周,还有几发脱靶。
  • 准确但不精确瞄准得没错,但是你的枪法有问题! 你的子弹全部打在了靶上,但是离靶心有一定距离。
  • 精确但不准确你的靶心,不是隔壁的! 你的子弹几乎正中靶心,但是那是你旁边射击员的靶子。这显然不是你的目标。
  • 既准确又精确你是个神枪手! 你的子弹全部正中靶心。

确认(verification)和验证(validation)

确认是指检查软件是否符合产品说明书,而验证是指检查软件是否符合需求

换言之,确认仅仅检查行为是否遵循计划,而验证则检查行为是否符合实际预期。

示例

这就像做实验,如果老师给了一份实验指南,错误地要求在编写程序前关闭电脑电源,那么就会有人争辩说:

是实验指南让我这么做的!

这就是确认。但是常人都会发现这其中的错误,意识到不开电脑就无法编写程序,这就是验证

备注

依照 IEEE 610.12-1990 (IEEE Standard Glossary of Software Engineering Terminology)的定义:

  • 确认(validation):是在特定开发阶段中,评估软件是否符合阶段开始前所定义条件的程序。
  • 验证(verification): 是在开发阶段后,评估软件是否符合规格需求的程序。

换句话说,程序确保产品符合客户需求,而验证程序确保产品符合要求及设计规格。确认程序确保“制造出正确的产品”(you built the right thing),也就是符合客户需求的产品,而验证程序确保“以正确的方式制造产品”(you built it right)。

质量和可靠性

可靠性并不等于质量,它只是质量的一个方面。质量是一个更广泛的概念,包括了可靠性性能可用性可维护性等等。

测试和质量保证

双方的工作实际上存在一些区别。让我们当一回复读机:

  • 软件测试员的目标是尽早发现软件缺陷,并确保其得以修复
  • 软件质量保证人员的主要职责是创建和执行改进软件开发过程并防止软件缺陷发生的标准和方法。

当然,由于工作的相似性,软件测试员和软件质量保证人员之间的界限有时候会变得模糊。


小测验

问题摘录与参考回答

假如无法完全测试某一程序,在决定是否应该停止测试时要考虑哪些问题?

答:
  • 覆盖率,即测试的范围;
  • 所剩的时间、金钱和其他成本,即测试的可行性;
  • 风险,即测试是否已经达到了预期的目标。
  • 正确性,即测试是否已经完成了确认和验证的过程。
  • ……

启动 Windows 计算器程序,输入 `5,000 - 5 =`(逗号不能少),观察结果。这是软件缺陷吗?为什么?

答:

这个问题已经无法在 Windows 10 中复现。

事实上在老版本的 Windows 计算器中,逗号会被视作小数点(与某些国家的习惯相符)。需要根据软件实际面向的用户群体来判断这个问题是否是软件缺陷。

假如测试模拟飞行或模拟城市之类的模拟游戏,精确度和准确度哪一个更值得测试?

答:

模拟游戏的主要目标是对现实情况的虚构模拟,因此模拟准确是第一要务,否则就会出现“出戏”的情况。

备注

你不会想在二战模拟游戏中看到一架 F-22 隐形战斗机,对吧?

此外还需要考虑游戏的硬核程度,它决定了对精确度的要求。如果是像 DCS 或者 ARMA 那样的战术拟真游戏,精确度就显得尤为重要。

有没有质量很高但可靠性很差的产品?举例说明。

答:

不可靠的产品的一个很容易想到的例子是一次性用品,它们在设计时就没有考虑重复使用,但这不妨碍它们在质量上有很高的要求。

另一个例子是高性能跑车。它们满足了提速、时速、外观、舒适度等等方面的要求,但是却需要频繁地保养与维护,修理费用也相对昂贵——但是,能够负担得起这些费用的人并不会认为这是严重的质量问题。

假如周一测试软件的某一功能,每小时发现一个新的软件缺陷,你认为周二将会以什么样的频率发现新的软件缺陷?

答:

根据第四条原则,我们可以推断周二发现新缺陷的频率会更高。

此外,从杀虫剂怪事原则的角度来看,我们也可以推断,再次执行同样的测试能够发现的缺陷会更少。

解释

这听起来有点矛盾。为什么会这样?

这两个事实实际上是不冲突的。前者描述了实际上缺陷的数量,而后者描述了我们能够感知到的缺陷的数量。这两个事实之间的关系就像是冰山的关系:我们只能看到冰山的一角,但是我们知道它的实际体积要远远大于我们看到的部分。