第二章  心理学、经济学与软件测试
软件测试是一个技术工作,但它也涉及一些重要的经济因素和心理学因素。
在理想的情况下,我们将会尝试检测某个程序的所有数据排列的可能性。然而在大多数的用例中,这种测试是不可能的。即使是看似很简单的程序,都可能有成百上千种输入和输出的组合。构建包含所有这些可能性的测试用例是不切合实际的,从经济的角度上来讲,构造复杂的应用测试需要花费较多的时间,投入大量的人力资源,所以不具有较高的可行性。
此外,软件测试人员需要持有正确的态度(也许愿景是一个更好的词)来完成应用软件的测试。在许多案例中,软件测试人员的态度比测试工作实施的过程更为重要。所以,我们将讨论我们将以怎样的态度对待软件测试,在这个话题开始之前,我们将深入研究技术性质这一主题。
测试中的心理学
产生测试错误的真正原因是由于大多数软件工程师给出了错误的定义来解释什么是软件测试。他们通常这样说:
l  测试是证明错误并不存在的过程。
l  测试的目的是证明程序能够正确的完成预期功能。
l  测试是建立信任的过程,确定程序在按照预期目标执行。
这些定义是颠倒的。
当某个程序的测试开始执行的时候,需要为这个程序加载一些数据,通过加载数据的方法提高对程序的质量和可靠性的测试,对程序可靠性的检测意味着将会找到并解决更多的问题。因此,测试不是为了表明该程序可以运行;相反,在开始测试之前应该假设该程序可能包含某些问题(对所有的程序都进行有效的假设)然后测试这个程序,尽量去发现这些可能存在的问题。
所以,更恰当的定义是:
测试是发现程序运行错误的过程
虽然这看起来像是一个微妙的语义游戏,但却是关键区别所在。了解软件测试的真正定义,对你的努力能否取得成功具有深远的意义。
人们往往以较高的奋斗目标来指导行动,建立正确的目标具有重要的心理暗示作用。如果我们的目标是证明程序中没有错误,那么我们会下意识的指导实现这个目标,也就是说,我们会倾向于选择造成程序失败的概率较低的测试数据;如果我们的目标是为了证明程序中存在错误,我们的测试数据很可能会提高发现程序缺陷的概率。显然后者比前者更具有测试价值。
测试的解释与很多定义有所关联,将分散在这本书中逐一讲解。举例来说,测试意味着破坏的过程、残酷的过程,这也可以解释为什么很多人觉得它很难完成。它也许与我们生活中的认知,是否有好运气,我们是否具有建设性的见解或者是否具有破坏性等等这些生活常识相违背。多数人都倾向于制造完整的对象,而不是分裂它们。制定什么样的测试用例(或者说测试数据),什么情况下程序能够执行,什么情况下不能够执行,三者之间具有必然的联系。
另一个增进对测试理解的方法是着重分析我们“成功”和“失败”这两个词,它们经常被项目经理用于评测测试执行结果。如果测试经理执行了一个没有找到程序中问题的测试用例,则会认为这个用例“执行成功”,相反,如果在执行这个用例时发现了新问题,通常会认为它“执行失败”。
另外,上述成功与失败的含义也可以被颠倒过来。就用“不成功”来表示该结果是不符合需求的或是令人难以接受的。按照我们的思维方式,当找到错误的时候意味着我们已经成功的构造和执行了一个软件的测试,那么这个用例就可以被置为“fixed”状态。同样在测试结束的时候没有发现更多的新问题,则认为该用例的执行是成功的。软件是否被完整的检查过并不是评价测试成功与否的唯一标准,在测试的过程中大多数用例的执行并没有问题的产生,很可能会认为这次测试是失败的,所以将程序执行是否发生错误作为评价测试结果的标准是不可靠的。
可以肯定执行过程中发现了错误的测试用例的执行是成功的,并且它已经被证明是一项有价值的投资。没有找到任何错误的测试用例,被看作是程序运行正确及运行结果正确的有力证明。
先来思考一个因为身体不舒服而需要看医生的问题。如果医生进行一些项目的检查后却没有发现哪出了毛病,我们就不能说他的检查是“成功”的,那么他们的检查就是失败的,患者花费了昂贵的检查费用但仍然承受着病痛,可能会对医生的诊断能力产生怀疑。但是,如果化验结果表明该患者患有消化性溃疡,那么这个检查就是成功的,因为医生可以根据诊断结果为患者治疗。因此,从医学的角度来理解这个词的含义似乎更恰当一些。以此类推,我们可以将待测试的程序看作是等待医生诊断的患者。
又如这些定义的第二个问题是“测试的目的是证明程序能够正确的完成预期功能”,事实上这个目标是不可能达成的,几乎是任何程序甚至是极小的程序都不可能不存在问题。
同样,心理学研究告诉我们,当制订了不可行或者不可能完成的目标时,工作业绩就会不佳。例如,要求在15分钟内完成星期日的纽约时报上的拼字游戏,结果显示几乎没有人能够在10分钟内取得进展,因为大多数人会觉得这项工作是不能够完成的。但是将时间修改为4个小时,那么我们可以期望在最初的10分钟内会取得一些进展。将测试定义为可行的发掘程序中的错误的过程,这个心理上的问题就可以解决了。
第三个定义的问题是“测试是建立信任的过程,确定程序在按照预期目标执行”,程序一直在按照预期的结果执行直到它发生错误为止,如果发生错误,那么这个错误应该是非常直观的。程序没有按期望的那样运行,这个条件应该加以说明“什么才是程序不应该做的”。重温第一章中关于三角形的问题。即使我们能够证明程序能够正确的区分不等边、等腰和等边三角形,如果程序没有按预期的目标执行仍然会发生一些错误(比如123代表一个不等边三角形,000代表一个等边三角形)。当我们将程序的测试看作是寻找错误的过程而不是程序应该做什么的过程时,我们更容易发现后一类错误。
总之,测试应被视为带有合理的破坏性行为的找出程序潜在错误的过程(执行时可以做一些假设条件),成功的测试案例能够充分展示导致程序失败的各项原因。当然,确定程序的最终运行标准,即什么是应该做的和不这样做是什么不应该做的非常重要。这个标准的制定离不开测试中的勤奋探索。
参考其他人采用的测试方法,结合自己的经验制定测试计划,你将会得到“完美”(无差错)的程序。最好的方法就是建立信心,尝试采用输入数据集,找到程序中不完善的地方,而不仅仅是确认程序运行正常。