软件测试的目的及原则 软件测试
一、软件测试的目的
误解1:软件测试的目的是为了确保没有Bug 这种看法反映了一种对于软件本质的乐观但从根本上错误的观点。一个简单的事实就是不存在“bug-free”的软件。 为什么是这样呢?首先,在等式的开发一边,你必须面对时刻在变化的技术,一个复杂的而且经常有缺陷的应用设计,集成新的已存在的系统带来的困难,等等。人本身的错误也是一个很大的因素。虽然现代思维应用开发工具可以自动生成代码,但是在有些地方人必须参与到开发过程中,而人是会犯错误的。 而在等式的测试这一边,不可能让你的产品在送到你的用户以前运行所有可能的测试来检测出每一个可能的bug。 让我们来看一个简单的假定的例子。比如说你要测试一个这样的程序: 接受3个整型的数值作为输入,每一个数值的范围在0到9之间。 在2种操作系统下运行。 可以访问存储在3个不同厂商中任何一个提供的数据库中的数据。 我们计算一下,我们有1,000种可能的排列作为测试输入。为了测试在每个操作系统上的每种排列,我们需要2,000个测试用例,另外再考虑到每种输入在每个支持的数据库运行一遍,我们需要6,000个测试用例。这个数字还没有考虑到其他的测试情况,例如网络故障,磁盘空间不足以及内存耗尽等等。所以实际上我们需要测试用例的数目要更大一些。 无疑,我们不得不接受这样一个事实:我们只能生活在一个所有的软件都有bug的世界当中。然而,我们没有必要绝望。经过精心的计划,我们可以选择性地找出产品中最多出现危险以及对我们的用户最重要的部分中的bug。下面是我发现的有效的一些步骤。 在你的计划当中加入风险分析 正确理解你的客户需求文档本身就是一门科学(后面将会详细讲到)。如果你不能直接接触到你的用户--例如,通过客户焦点小组,那么你就应该和你的客户支持部门一起商讨你的测试计划,因为他们直接接触到最终用户。 要明白你的产品哪些部分处于危险当中同样需要分析。变更是危险的主要来源;如果你引入了一个变更,你可能不注意地引入了一个新的bug或者发现一个已经存在的bug。因此,支持新功能的代码一直是一个寻找危险的好地方。为了修正一个bug而修改的代码也是这样。而且,如果你在某个地方发现了bug,那么在附近潜藏着其他bug的可能性就很大。虽然你可能认为经过多年修正了很多bug的地方最后“清除干净了”,这种想法只是在修正时发现了bug的根源的情况下才是正确的。如果bug的根源是糟糕的设计,而进行的修正只是一个简单的补丁而不是从根本上解决这个问题,那么这个修正实际上可能引入了新的bug。另外,记住:即使是基于“根本原因”的修正也有可能会引发基础性变更,暴露其他严重bug。 理解产品是如何工作的--和为何可能出故障 对一些测试者来说,第一个想做的就是看产品外在的可见的“行为”--将精力集中在他们的产品客户将看到的部分。这样做效力有限,因为他们没有清楚的理解产品程序的逻辑,数据流等等,这些是用户不可见的。为了能够理解产品是如何工作的,以及怎样会出故障,你必须看“罩子下面”并且在你的测试中用到你看到的东西。2 例如,如果你只看一个GUI,你可能看到程序通过一个格式化的HTML表格显示一个特定的数据库查询的结果。然而,除非你知道这个表格的表示是一个Java数组对象,从服务器传到客户端,然后转化为一个HTML表格,否则你就不会知道这里存在一个潜在的一个客户端性能瓶颈的危险。如果一个用户运行一个查询,返回的记录太多,就会导致客户端在处理表格的时候像死机一样。(我在几年前是通过这样的方法解决这个问题的:每次让客户端只接收一部分结果数据,并且明确地告诉用户还有其他的数据未传过来。) 如果有充足的时间设计和进行测试,你总是可以找到更多的bug。然而,如果那个bug好像对你的客户影响不大,那就不值得花时间和精力去找到它。去搜索每一个可能导致系统在5,000年发生一次故障的bug是没有意义的,因为那可能需要你花5,000年去运行所必要的测试。3 花时间去找出哪里可能藏有真正有影响的bug,并将测试集中于那些地方,会好很多。 理解客户究竟会怎样去使用产品 之前,我间接提到了通过直接接触实际用户或者通过你公司用户服务部门去了解用户需求的重要性。通过同样的渠道,你也应该确认你的测试计划是否反映了你用户的系统配置,特殊需求以及吞吐/系统能力需求。 这也需要了解你的客户的条件限制,这些限制将直接影响用户怎样使用你的产品。在我加入Rational之前,我的工作是有关一个Internet防火墙,它能够支持常被称之为“split-brained DNS”功能网络配置功能。这个功能使用户能够在他们的防火墙后面维护一个私有的DNS服务器。然而我们发现,一些内部DNS服务器被错误的配置了,在我们没有更正他们的DNS 配置之前,无法使防火墙正常工作。最后我们不得不更改我们的安装工具使得即使在用户的内网断了的情况下防火墙仍能够正常运行。这样我们就可以把修理他们的网络当做一个独立的(收费的)任务。 现在让我们转到第二个误解。如果我们接受了bug-free软件真的是不存在的这一观念,我们可以通过运行测试找到故障,那么我们要测试到出故障,对吗?但是如果测试中出故障是一个好事情,那么我们是否能够把它叫做“失败”呢?误解2:软件测试的目的是为了验证软件能够正常运转 和第一个误解一样,这个说法也反映了一个对软件测试完全乐观的观点。在我们一生的活动中,我们尽力去创造和建造能够正常运行的事物,我们尽我们最大的努力去避免故障。然而,软件测试人员必须有不同观念:为了能够成功,我们必须有意地尽量去促使故障的产生。4 如果我们不采用“不正当的”方法会发生什么?如果我们设计避免故障的测试,那么将会使我们的客户失望。当你开发一个软件应用程序的时候,你会清楚地了解应用程序所使用的数据类型,配置以及它能运行所需要的环境。你也知道程序的局限性。如果你的目标是验证应用程序能够工作,你就会限制你在数据、配置和应用程序最初设计所支持环境的边界处测出故障的可能。如果你这样做,你有较大的机会通过你所有的测试。然而在现实世界中,你的客户很有可能会超越这些边界并遇到你测试中没有测出来的bug。 下面是一些要成为一个好的测试者所需要的可以使用的建议。 如果产品出现了故障,你就进行了一个成功的测试。 如果你在头脑中保持测试的目标是为了发现一个bug这一观念,那么你就可以开始考虑一个“成功”的测试就是让软件运行出现故障。不论你只是运行了一个测试还是运行了成千上万次测试,即使你没有发现bug,你的软件仍然不能说没有bug。bug仍然潜伏在测试没有覆盖到的领域。换句话说,要证明没有bug是一件非常困难的事情,并且,我们前面提到过,你必须集中力量去找到产品中危险最大的领域中的bug。 不久前,我接受了一个产品的测试任务,在我之前这个产品已经经过了成百上千次测试。产品出来以后,他们所有人对产品的一些过去投入了几年的工作的组件进行测试。然而,他们的测试很少甚至没有涉及到感兴趣的测试领域。虽然这种回归测试有利于验证新代码的变更没有导致一些旧的函数无法运行,但是我不得不在可能导致麻烦的区域设计新的测试。在 软件测试的艺术,5 一书中,Glenford Myers用了一个医学上的类比,如果你觉得不舒服去医院检查,但检查的结果并不足以诊断病因,那能够说这个检查是“成功”的吗?不!你还是有病,你的医生必须再进行正确的检查。 所有的使用者都会犯错误 在测试一个新的软件应用程序的时候,看到不好的测试结果的人肯定要反对你的测试场景。“没有人会那样做!”。不要相信没有这个。一些用户会那样做,或者做一些更糟的事情,并且他们不是有意那样。你的工作就是在产品运送到客户手里以前,考虑用户会犯的错误中最坏的情况,并且确认你的产品仍然能够安然无恙,没有崩溃或者丢失数据。再说一遍,你要寻求的是那些能够发现危险bug的测试故障。 让我们再看一下我们之前讨论的简单程序,那个需要6,000次测试才能包括所有可能的程序。如果你要设计只在合法的输入,环境,操作等情况下的测试,那么你的测试只涵盖了对你系统运行来说最好的场景。但是,如果有些地方出错会怎样?如果用户手指滑了一下,或者错误的配置了什么,或者删除了非常重要的信息,你的软件会怎样表现?或者当一个系统/服务器出现挂起,或者出现达到一些资源的上限(比如内存,磁盘空间,数据库记录的ID等),会发生什么?当一些应该被标识为损坏的数据进入或者通过系统会怎么样?如果操作中断,系统处于含糊不清的状态?或者如果太多的人在同样的时间做同样的事情?潜在错误的列表是无限的,并且如果你只想确认“它可以工作”的话,你可能就会忽略掉这些场景中的大部分。
二、软件测试的原则应该是:
(1)应当把“尽早地和不断地进行软件测试”作为软件开发者的座右铭。
由于原始问题的复杂性,软件的复杂性和抽象性,软件开发各个阶段工作的多样性,以及参加开发各种层次人员之间工作的配合关系等因素,使得开发的每个环节都可能产生错误。所以不应把软件测试仅仅看作是软件开发的一个独立阶段,而应当把它贯穿到软件开发的各个阶段中。坚持在软件开发的各个阶段的技术评审,这样才能在开发过程中尽早发现和预防错误,把出现的错误克服在早期,杜绝某些隐患,提高软件质量。
(2)测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成。
测试以前应当根据测试的要求选择在测试过程中使用的测试用例(Test case)。测试用例主要用来检验程序员编制的程序,因此不但需要测试的输入数据,而且需要针对这些输入数据的预期输出结果。如果对测试输入数据没有给出预期的程序输出结果,那么就缺少了检验实测结果的基准,就有可能把一个似是而非的错误结果当成正确结果。
(3)程序员应避免检查自己的程序。
测试工作需要严格的作风,客观的态度和冷静的情绪。人们常由于各种原因具有一种不愿否定自己工作的心理,认为揭露自己程序中的问题总不是一件愉快的事。这一心理状态就成为测试自己程序的障碍。另外,程序员对软件规格说明理解错误而引入的错误则更难发现。如果由别人来测试程序员编写的程序,可能会更客观,更有效,并更容易取得成功。要注意的是,这点不能与程序的调(debuging)相混淆。调试由程序员自己来做可能更有效。
(4)在设计测试用例时,应当包括合理的输入条件和不合理的输入条件。
合理的输入条件是指能验证程序正确的输入条件,而不合理的输入条件是指异常的,临界的,可能引起问题异变的输入条件。在
试程序时,人们常常倾向于过多地考虑合法的和期望的输入条件,以检查程序是否做了它应该做的事情,而忽视了不合法的和预想不到的输入条件。事实上,软件在投入运行以,用户的使用往往不遵循事先的约定,使用了一些意外的输入,如用户在键盘上按错了键或打入了非法的命令。如果开发的软件遇到这种情况时不能做出适当的反应,给出相应的信息,那么就容易产生故障,轻则给出错误的结果,重则导致软件失效。因此,软件系统处理非法命令的能力也必须在测试时受到检验。用不合理的输入条件测试程序时,往往比用合理的输入条件进行测试能发现更多的错误。
(5)充分注意测试中的群集现象。
测试时不要以为找到了几个错误问题就已解决,不需继续测试了。经验表明,测试后程序中残存的错误数目与该程序中已发现的错误数目或检错率成正比。根据这个规律,应当对错误群集的程序段进行重点测试,以提高测试投资的效益。
在所测程序段中,若发现错误数目多,则残存错误数目也比较多。这种错误群集性现象,已为许多程序的测试实践所证实。例如美国IBM公司的0s/370操作系统中,47 9/6的错误仅与该系统的4%的程序模块有关。这种现象对测试很有用。如果发现某一程序模块似乎比其他程序模块有更多的错误倾向时,则应当花费较多的时间和代价测试这个程序模块。
(6)严格执行测试计划,排除测试的随意性。
测试计划应包括:所测软件的功能,输入和输出,测试内容,各项测试的进度安排,资源要求,测试资料,测试工具,测试用例的选择,测试的控制方式和过程,系统组装方式,跟踪规程,调试规程,以及回归测试的规定等以及评价标准。对于测试计划,要明确规定,不要随意解释。
(7)应当对每一个测试结果做全面检查。
这是一条最明显的原则,但常常被忽视。有些错误的征兆在输出实测结果时已经明显地出现了,但是如果不仔细地全面地检查测试结果,就会使这些错误被遗漏掉。所以必须对预期的输出结果明确定义,对实测的结果仔细分析检查,抓住征候,暴露错误。
(8)妥善保存测试计划,测试用例,出错统计和最终分析报告,为维护提供方便。
文章来源于领测软件测试网 https://www.ltesting.net/