关于调试:Bug Hunting Strategies?

Bug Hunting Strategies?

假设您在对软件相当复杂的部分进行功能测试时发现了一个错误。
它可能源于数据库中的错误/意外数据、中间层代码或前端中的某些东西。

很好。我们都去过那里。

你有单元测试要写


我发现 Rubber Duck 调试策略也很有效。


  • 在调试环境中重现错误。
  • 检查错误发生时的系统状态,以找到直接明显导致错误发生的不一致/不正确/意外的状态元素。通常,只需查看代码和调用堆栈就会立即告诉您问题所在。
  • 将测试添加到可以在正常控制流中创建/改变此状态的所有点。
  • 将这些测试的失败视为新错误,返回到第二步。
  • 冲洗,起泡,重复直到找到问题的最初原因。乏味和机械,但会带你到那里。

    除了...有时第 3 步迭代中的测试不会失败;最常见的是,因为一些不相关的系统损坏内存是导致无效状态的原因,或者因为问题与线程/定时/未初始化数据相关,并且引入测试会改变时序和/或数据布局,足以改变或隐藏症状。在这一点上,至少对于这张海报来说,这个过程变得更加直观,在用侵入性较小的形式替换健全性测试和选择性地禁用模块以排除损坏源之间交替。


    根据我的经验,最好按照直觉 (1) 进行 30 分钟左右。

    如果没有任何结果,请与其他人谈谈。

    与其他人交谈(即使他们不是技术人员)能提供帮助真是太神奇了。


    在这种情况下,我的第一步通常是按照可以最快减少要检查的内容数量的顺序检查内容。您几乎可以将其视为对 bug 进行二进制搜索:"嗯,POST 参数看起来正确,所以我可以在表单提交之前排除所有内容,"等。

    也就是说,如果我强烈认为问题可能出在某个特定位置,我会先检查一下。


    我会说这没关系,只要它有文档且有条理。有时以随机顺序做事比花大量时间试图找出"最佳"方式更有效,这是编程中一个奇怪的小真理。

    永远不要低估直觉;那是让您注意的经验。我几乎总是从你可能认为是我的"直觉"的感觉开始。我查看了错误,并检查了我认为可能导致此类问题的步骤。


    我和@moonshadow 在一起,但我会补充一点,这在某种程度上取决于失败的原因。也就是说,某些类型的故障有相当众所周知的原因,我会从已知原因开始

    例如,在 Windows 系统上,"访问冲突"错误几乎总是由于尝试使用或查看(访问)未分配的内存。要找到此类错误的根源,最好查看所有分配(或未分配)内存的位置。

    如果已知"问题"是由错误数据引起的,则修复可能需要更改数据验证或采集,即使错误被追踪到分析。

    还有一点,在考虑错误时,尝试创建一个小程序来创建它通常是非常值得的。


    一般来说,我从我认为最有可能的罪魁祸首的假设子集开始,然后根据每个假设的反驳难易程度对该假设子集进行排序,然后从最简单的假设开始。

    不管顺序如何,重要的是你如何处理你的假设。开始尝试反驳每个假设而不是验证它,您将覆盖更多领域(请参阅 Richards J. Heuer, Jr. 的《智力分析心理学》,免费 PDF)。


    在软件工程电台听专家如何调试软件:

    Dave Thomas 谈到了软件考古学,其中有一些非常棒的调试技巧。

    Andreas Zeller 出现在专门用于调试的一集中。


    首先,我尝试了解错误,然后根据直觉执行您建议的所有操作。
    这实际上是您对特定原因的确定程度以及测试的容易程度之间的权衡。

    此外,当我调查原因时,我尝试直接添加真正快速的检查,因为我正在检查代码(添加一些临时调试输出语句,添加断言等)


    我倾向于凭直觉和分而治之的方法;在我认为"错误"所在的地方隔离大小减小的代码块。

    如果您不知道或不了解代码库,这将不起作用 - 如果是这种情况,请找一个懂的人,并按照他们的直觉行事。


    n


    我通常这样做:

    1) 向自动化回归测试系统添加一个新的功能测试用例。我通常使用

    使用自己的回归测试系统启动软件项目

    • 用于控制 SCSI/IDE 接口/设备的 Excel VBA C 库(13 年前),测试报告为 Excel 电子表格。
    • TCL Expect 用于复杂网络路由器系统测试。测试报告是网页。 (6年前)
    • 今天我使用 Python/Expect。测试报告是 XML python base XML 分析器。

    所有这些工作的目标是确保一旦发现任何错误,它就不会再次出现在签入代码或生产系统中。此外,更容易重现随机和长期问题。

    不要签入任何代码,除非它经过一夜自动回归测试。

    我通常在产品代码与测试代码之间编写 1:1 的比率。 20k 行 TCL 专家为 20K 行 C 代码。 (5 年前。)例如:

    • C 代码将实现设置隧道 tcp 连接转发代理。
    • TCL 测试用例: (a) 设置连接确保数据通过。 (b) 建立与不同网络元素的连接。 (c) 重复 10、100、1000 次并检查内存泄漏和系统资源问题等。
    • 对系统中的每个功能都执行此操作,可以看出为什么测试程序与代码的 1:1 比例。

    我不希望 QA 团队使用我的测试系统进行自动化测试,因为我所有的签入代码都必须通过测试。在将代码提供给 QA 团队之前,我通常会运行 2 周的长期回归测试。

    运行手动测试用例的 QA 团队还确保我的程序有足够的内置诊断信息来捕获任何未来的错误。目标是有足够的诊断信息在 2 小时内解决 95% 的错误。在我的上一个项目中,我能够做到这一点。 (RBG Networks 的视频网络设备。)

    2) 添加诊断程序(现在是网络库)以获取所有内部信息。 (当前状态、日志等)。 > 我的代码(特别是 c/c)的 50% 是诊断代码。

    3) 为我不理解的问题区域添加更多详细信息。

    4) 分析信息。

    5) 尝试修复错误。

    6) 通宵/周末进行回归测试。当我在 R


    这里有一些有用的提示:

    • 如果您使用的语言会从那里开始生成异常堆栈跟踪。
    • 如果可以,请获取导致问题的原始数据的副本。
    • 使用好的调试器。
    • 如果您可以访问其中一个,那么各种语言的 ODB 之类的东西会很有帮助,因为它允许您在事件发生后快速前进或后退执行
    • 排除不可能,您将获得解决方案!

    我的订单:

  • 查看 1-2 个最可能原因的代码(根据直觉选择)。
  • 如果没有找到,在调试器中执行代码(或者如果不可能,在代码中插入调试/记录语句)。
  • 如果没有找到,请打电话给其他人并与他/她一起重复步骤 1 和 2。