读者可以考虑一下倘若编译程序能够正确地指出代码中的所有问题,那相应程序的错误 情况会怎样?这不单指语法错误,还包括程序中的任何问题,不管它有多么隐蔽。例 如,假定程序中有“差1”错误,编译程序可以采用某种方法将其查出,并给出如下的错 误信息 -> line 23: while (i<=j) off by one error: this should be '<' 又如,编译程序可以发现算法中有下面的错误: -> line 42: int itoa(int i, char* str) algorithm error: itoa fails when i is -32768 再如,当出现了参数传递错误时,编译程序可以给出如下的错误信息: -> line 318: strCopy = memcpy(malloc(length), str, length); Invalid argument: memcpy fails when malloc returns NULL 好了,要求编译程序能够做到这一程度似乎有点过分。但如编译程序真能做到这些,可 以想象编写无错程序会变得多么容易。那简直是小事一桩,和当前程序员的一般作法真 没法比。 假如在间谍卫星上用摄像机对准某个典型的软件车间.就会看到程序员们正弓着身子趴 在键盘上跟踪错误;旁边,测试者正在对刚作出的内部版本发起攻击,轮番轰炸式地输 入人量的数据以求找出新的错误。你还会发现,测试员正在检查老版本的错误是否溜进 了新版本。可以推想,这种查错方法比用上面的假想编译程序进行查错要花费大得多的 工作量、确实如此,而且它还要有点运气。 运气? 是的,运气。测试者之所以能够发现错误,不正是因为他注意到了诸如某个数不对、某 个功能没按所期望的方式工作或者程序瘫痪这些现象吗?再看看上面的假想编译程序给 出的上述错误:程序虽然有了“差1”错误,但如果它仍能工作,那么测试者能看得出来 吗?就算看得出来,那么另外两个错误呢? 这听起来好象很可怕但测试人员就是这样做的大量给程序输入数据,希望潜在的错误能 够亮相。“噢,不!我们测试人员的工作可不这么简单,我们还要使用代码覆盖工具、 自动的测试集、随机的“猴”程序、抽点打印或其他什么的”。也许是这样,但还是让 我们来看看这些工具究竟做了些什么吧!覆盖分析工具能够指明程序中哪些部分未被测 试到,测试人员可以使用这一信息派生出新的测试用例。至于其它的工具无非都是“输 入数据、观察结果”这一策略的自动化。 请不要产生误解,我并不是说测试人员的所作所为都是错误的。我只是说利用黑箱方法 所能做的只是往程序里填数据,并看它弹出什么。这就好比确定一个人是不是疯子一 样。问一些问题,得到回答后进行判断。但这样还是不能确定此人是不是疯子。因为我 们没法知道其头脑中在想些什么。你总会这样地问自己:“我问的问题够吗?我问的问 题对吗……”。 因此,不要光依赖黑箱测试方法。还应该试着去模仿前面所讲的假想编译程序,来排除 运气对程序测试的影响,自动地抓住错误的每个机会。
要点: l 消除程序错误的最好方法是尽可能早、尽可能容易地发现错误,要寻求费力最小的自 动查错方法。 l 努力减少程序员查错所需的技巧。可以选择的编译程序或lint警告设施并不要求程序 员要有什么查错的技巧。在另一个极端,高级的编码方法虽然可以查出或减少错误,但 它们也要求程序员要有较多的技巧,因为程序员必须学习这些高级的编码方法。