误解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。

理解产品是如何工作的--和为何可能出故障

对一些测试者来说,第一个想做的是看产品外在的可见的“行为”--将精力集中在他们的产品客户将看到的部分。这样做效力有限,因为他们没有清楚的理解产品程序的逻辑,数据流等等,这些是用户不可见的。为了能够理解产品是如何工作的,以及怎样会出故障,你必须看“罩子下面”并且在你的测试中用到你看到的东西。

例如,如果你只看一个GUI,你可能看到程序通过一个格式化的HTML表格显示一个特定的数据库查询的结果。然而,除非你知道这个表格的表示是一个Java数组对象,从服务器传到客户端,然后转化为一个HTML表格,否则你不会知道这里存在一个潜在的一个客户端性能瓶颈的危险。如果一个用户运行一个查询,返回的记录太多,会导致客户端在处理表格的时候像死机一样。(我在几年前是通过这样的方法解决这个问题的:每次让客户端只接收一部分结果数据,并且明确地告诉用户还有其他的数据未传过来。)

如果有充足的时间设计和进行测试,你总是可以找到更多的bug。然而,如果那个bug好像对你的客户影响不大,那不值得花时间和精力去找到它。去搜索每一个可能导致系统在5,000年发生一次故障的bug是没有意义的,因为那可能需要你花5,000年去运行所必要的测试。3 花时间去找出哪里可能藏有真正有影响的bug,并将测试集中于那些地方,会好很多。

理解客户究竟会怎样去使用产品

之前,我间接提到了通过直接接触实际用户或者通过你公司用户服务部门去了解用户需求的重要性。通过同样的渠道,你也应该确认你的测试计划是否反映了你用户的系统配置,特殊需求以及吞吐/系统能力需求。

这也需要了解你的客户的条件限制,这些限制将直接影响用户怎样使用你的产品。在我加入Rational之前,我的工作是有关一个Internet防火墙,它能够支持常被称之为“split-brained DNS”功能网络配置功能。这个功能使用户能够在他们的防火墙后面维护一个私有的DNS服务器。然而我们发现,一些内部DNS服务器被错误的配置了,在我们没有更正他们的DNS 配置之前,无法使防火墙正常工作。后我们不得不更改我们的安装工具使得即使在用户的内网断了的情况下防火墙仍能够正常运行。这样我们可以把修理他们的网络当做一个独立的(收费的)任务。

现在让我们转到第二个误解。如果我们接受了bug-free软件真的是不存在的这一观念,我们可以通过运行测试找到故障,那么我们要测试到出故障,对吗?但是如果测试中出故障是一个好事情,那么我们是否能够把它叫做“失败”呢?