发现错误的诀窍

一旦你已固定了某个错误且求精了产生错误的测试用例,找到其错误源的工作可能是繁琐
的或富有挑战的,这取决于你所编代码的好坏。你可能由于所编代码质量不高费了不少时间才
找到错误。你也可能不愿听到这些,但这是真实的。如果你遇到了麻烦,可采用以下方法:

   使用所有可能数据进行假设。当你对错误源进行假设时,你应考虑尽可能多的数据。在上例
中,你可能注意到Fruit-Loop,Frita所在位置并不正确于是你作出“F”开头的名字的排序是不
正确的。这是一个不正确的假设,因为它并不能解释Medula,Midred 也是处于不正确位置或第
二次排序是正确的这个事实。如果数据并不符合假设,你也不应抛弃这些数据——问问它们为
何不符合并重新作出假设。
    对上例的第二个假设,是认为错误来自带有下横线的名字,而不是单个输入的名字。它似
乎也不能解释名字第二次输入时排序是正确的这个事实。然而,第二个假设是更能证实错误的
较为求精的假设。刚开始假设不能解释所有数据是很自然的,但是只要你保持对假设求精,最
终是能和有关数据是吻合的。

   求精产生错误的测试用例。如果你不能发现错误源,可试着进一步求精测试用例。你可使
一个常量取代你所设想的还要多的值,你侧重于某一个常量可使你取得重要的突破。

    通过不同的方式再生错误。有时试用相似但并不相同的测试用例是有益的。如你用某个测
试用例得到一个错误修改,而用另一测试用例得到另一个错误的修改,你就能确定错误之所在。
通过不同的方法再生错误有助于确诊产生错误的原因。一旦你认为判明了某个错误,试运
行一个产生类似错误的测试用例。如果此测试用例产生了错误,你也就懂得问题之所在了。错
误常常源于各种因素,仅用某一测试来论断错误有时并不能发现问题根本之所在。

    生成更多的数据以产生更多的假设。选择测试用例然后运算它们,以产生更多的数据,将
其加到你的可能假设中去。

    使用否定测试的结果。设想你建立了一个假设并运行了一个测试用例来证实它。再假定有
一测试用例否定了你所作假设,如果你还是不知道错误之所在。你仍需要有新的测试用例——
即错误并不是发生在你所认为的领域。这缩小了你的研究领域和可能的假设范围。

    提出尽可能多的假设。不是将自已限制在一个假设之中,你应尽可能提出更多的假设。你
首先不必分析它——你只需提出尽可能多的假设,然后检查每个假说并考虑用测试用例证实或
否定它。这种智力练习是有益的。因为它有助于打破由于侧重于某一个原因所引起的调试僵局。

    缩小可疑代码区域。如果你正在测试整个程序,或整个模块、子程序,你应测试较小的部
分。有条理地移去部分程序,再看看错误是否还发生。否则,你就知道了你所移去的那部分程
序中含有错误。而移去部分程序后错误还发生。你就知道错误发生在留下的那部分程序中。 
    你应细分和诊断整个程序,而不是任意地移去程序的某个部分。对你的寻找采用二分搜索
算法。首先试着移去一半的代码,并确定这一半是否存在错误,然后将二分这部分代码。并检
查其中的一半是否含有错误,继续二分下去,直到你发现错误为止。
    如果你使用了许多小的子程序,你可通过注释对子程序的调用来达到细分整个程序的目的。
或者,你可通过使用预处理命令移去代码。
    如果你使用了调试程序,你不必移去代码,你可在程序中某处设置断点,然后检查运行结
果。如果你的调试程序允许你跳过对子程序的调用,你就可跳过对一些子程序的执行,然后再
看看错误是否发生。调试过程和将程序的某些部分作物理移去是相似的。

    怀疑已发生过错误的子程序。已发生过错误的子程序有可能发生错误。在过去已发生过麻
烦的子程序比以前未发生过错误的子程序更有可能含有一个新的错误。再检查发生过错误的子
程序。

    检查最近修改过的子程序。如果你不得不诊断一个新错误,它通常和最近作过修改的代码
有关。它可能是全新的代码或已修改过的旧的代码。如果没有发现错误,你可运行一下程序的
旧版本,看看是否有错误发生。如果也没有发生错误,你就能明白发生在新版本中的错误是由
子程序中的相互作用所引起。

    扩展可疑代码区域。将注意力集中在代码的某一小部分区域是容易的,因为你确信“错误
必定发生在这段代码中”。如果你没有发现错误,考虑错误不在本段代码的可能性。扩展你所怀
疑的代码区域,然后用二分法寻找其中的错误。

    逐步集成。如果你每次在系统中加进一部分代码,调试的进行是容易的。如果在增加代码
后你发现了一个新的错误,你可再移去这部分代码并单独调试它。借助于测试工具运行子程序,

你就可确定它是否错了。

    耐心检查。 如果你使用集成方法并发现了一个错误,你就可测试某一小段代码以检查错误。
有时你可运行集成代码而不是分解代码并检查新的子程序来发现错误。对集成系统运算测试用
例,可能需花费较多的时间,而运行某一段特定代码花费的时间会少得多。如果前一、二次你
没有发现错误,你就得运行整个系统,忍辱负重,分解代码并单独调试新的代码。

    为迅速调试设立最大时间。 人们往往习惯于进行迅速的猜测而不是有系统地测试代码以发
现全部错误。我们中间的赌徒往往愿意采用五分钟的时间就可能发现错误的方法,而不用花半
小时发现错误的稳重方法。问题在于如果五分钟方法不顶用的话,你会变得固执。想通过捷径
发现错误,往往是数小时的时间白白流逝而毫无收获。 
    当你决定采用速胜方法时,你应为其确定一个最大时间限制。如果你超过了时间限制,你
应认为错误较难发现而不像你最初所想那样简单,这里你应改走较为费事的查错方法。这种方
法能轻易地发现简单的错误而发现较隐蔽的错误也只需花较长一点的时间。

    检查一般错误。使用代码质量检查表以激发你能考虑各种可能错误。如果你能遵循第24.2
节所示的检查习惯,你就将拥有你所在环境中,常见错误的良好检查表。你也可使用贯穿于本
书的检查表。请参看目录后的“检查表”。

   跟其它人谈论有关问题。有些人称这为“交谈调试”。在你向别人解释问题的过程中你往往
就发现了错误。例如,如果你在向别人解释工资程序中出现的问题,你可能会这样:“喂,Jennifer,
你有时间吧?我遇到了一个问题。我希望程序能对我的雇员工资单进行排序,但是一些名字的
排序是不正确的。当我将其打印出来除第一次外其它各次都是正确的。我检查问题是否输入新
名字所致,于是我试了一些,发现并无问题。我知道当我第一次打印时程序是能对名字正确排
序的,因为程序在雇员名字输入时对其排序,在保存时再一次排序,当输入雇员名字时程序并
不对其排序。原来问题在这里。真是谢谢你,Jennifer,你对我帮助很大。”
    Jennifer没有说一句话,你同时也解决了你的问题。这种结果是典型的并且这种方法对你解
决不同的错误是非常有效的。

    暂时终止对问题的考虑。有时你非常专注,以致于你无法清醒地思考问题。有多少次你暂
停下来去喝一杯咖啡当你向咖啡器走去时,你突然明白了问题的解答?或者在午饭时?或者在
回家的路上。如果你的调试并无进展而且你已经尝试了各种选择,你应休息一下。或去散步,
或作一下别的什么事情。让你的下意识在不自觉中得出对问题的解答。
    暂时放弃调试的作用在于减少因调试而带来的焦虑。焦虑的出现是你应休息一下的信号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值