欢迎来到测试与调试的世界!
你有没有试过写好一段程序,按下“执行”后……却什么都没有发生?或者更惨,它出现了一些莫名其妙的结果?别担心——每一位程序员,从新手到 Google 的专家,都曾遇过这种情况!测试 (Testing) 与 调试 (Debugging) 就是计算机科学中的“侦探技能”。在这个章节中,我们将学习如何找出错误(Bug)、如何修复它们,以及如何从一开始就预防错误发生。让我们开始吧!
1. 程序错误的类型
在解决问题之前,我们必须先理清问题的性质。你将会遇到三大类的错误:
语法错误 (Syntax Errors)
你可以把它想象成代码中的“文法错误”。如果你拼错了关键字,例如写成 prnt() 而不是 print(),或者在 if 语句的结尾忘了加冒号,计算机甚至无法启动你的程序。因为它根本听不懂你的指令。
运行时间错误 (Run-time Errors)
程序开始执行了,但却在运行过程中突然“崩溃”。常见的例子是试图除以零 \( (x / 0) \),或是尝试打开一个不存在的文件。指令本身的逻辑没错,但计算机在运行时撞上了一道无法跨越的“砖墙”。
逻辑错误 (Logic Errors)
这些是最棘手的!程序完美运行且不会崩溃,但输出结果却是错的。例如,如果你想计算 \( 2 + 2 \),却不小心输入成 2 * 2,计算机会给你 4。它完全执行了你给的指令,但你给的指令本身就是错的!逻辑错误是由程序员找出,而不是计算机。
快速回顾:
• 语法错误: 计算机听不懂“语言”。
• 运行时间错误: 计算机在运行时“绊倒了”。
• 逻辑错误: 计算机完美执行指令,但指令内容错误。
2. 寻找“Bug”(调试技巧)
我们该如何找出问题出在哪呢?以下是你侦探工具包中最有效的法宝:
手动模拟 (Manual Dry Run) 与 追踪表 (Trace Tables)
手动模拟 (Manual Dry Run) 是指你拿出纸笔,亲自扮演计算机的角色。你逐行阅读代码,并记录变量数值的变化。我们使用 追踪表 (Trace Table) 来整理这些变化。
例子: 如果你写了一个累加数字的循环,你的追踪表栏位可以设为“循环计数器”和“总计变量”。这能帮你精确找出逻辑在第几个步骤失败。
使用输出语句 (Print Statements)
有时候你需要“X 光视力”来观察程序内部发生了什么。通过在不同的步骤插入 print() 语句,你可以检查变量是否存有你预期的数值。
小贴士:如果你的程序执行到一半停止,试着加上 print("已到达第 1 步") 来查看程序运行到哪里中断!
回溯法 (Backtracking)
如果你在程序的最后发现了错误,回溯法意味着从发现错误的位置开始,向后检查代码,以找出错误的源头。
渐进式测试 (Incremental Testing) 与 注释掉代码 (Commenting Out)
渐进式测试是指先写一小段代码并测试它,然后才进入下一部分。千万不要一次写 100 行!如果你有一大段代码无法运作,你可以把其中的部分代码注释掉(在 Python 中使用 # 符号),以隔离出导致问题的区块。
关键重点: 不要只盯着屏幕想找出错误。请善用追踪表来理清逻辑、用 print 语句来查看“实时”数据,并将程序拆分成小区块来测试!
3. 数据验证:检查输入
计算机科学中有句名言:“垃圾进,垃圾出”(Garbage In, Garbage Out, GIGO)。如果你的程序期望输入“年龄”,但用户输入了“香蕉”,程序就会崩溃。数据验证 (Data Validation) 是由计算机执行的检查,确保输入的数据在处理前是“合理”或“有效”的。
常见的验证检查:
• 存在性检查 (Presence check): 确保数据确实被输入(栏位没有留空)。
• 范围检查 (Range check): 检查数值是否在特定限制内(例如,年龄必须介于 0 到 120 之间)。
• 长度检查 (Length check): 检查输入是否具有正确的字符数(例如,密码必须至少 8 个字符)。
• 格式检查 (Format check): 确保数据符合特定模式(例如,邮政编码格式)。
• 存在性检查 (Existence check): 检查该数据是否已存在于系统中(例如,检查用户名是否已被注册)。
• 校验码 (Check digit): 在数字(如 ISBN 或条码)后加上的一个额外数字,利用数学公式验证数字是否输入正确。
发现无效数据该怎么办?
• 对于交互式输入(用户正在输入时):程序应显示错误信息,并要求重新输入。
• 对于非交互式输入(如读取文件):程序通常应该结束执行或记录错误,因为无法要求文件提供“更佳”的数据。
4. 设计测试案例
为了 100% 确保你的程序运作正常,你需要使用不同类型的数据进行测试。这些称为 测试案例 (Test Cases)。假设你正在测试一个接受 0 到 100 分考试成绩的程序。
1. 正常数据 (Normal Data)
应该毫无问题地被接受的数据。
例子:25, 50, 85。
2. 边界数据 (Boundary/Extreme Data)
处于允许范围“边缘”的数据。逻辑错误往往就藏在这里!
例子:0 和 100(允许的最小值和最大值)。
3. 错误数据 (Error/Invalid Data)
程序应该拒绝的数据。这用来测试你的验证机制是否有效。
例子:-5, 105, "abc"。
你知道吗? 很多 Bug 的产生是因为程序员忘了测试边界数据。他们测试了“50”是否有效,却忘了检查程序是否能准确接受“0”或“100”!
快速回顾箱:
设计测试时,请务必选择:
1. 中间范围的数据 (正常数据)
2. 极限范围的数据 (边界数据)
3. 完全错误的数据 (错误数据)
总结清单
如果觉得内容很多,不用担心!只要记住这些核心重点:
• 使用 追踪表 (Trace Tables) 来逐行推敲代码。
• 语法错误是文法问题;逻辑错误是结果问题。
• 数据验证可以防止“垃圾”数据进入你的程序。
• 永远要用 正常、边界和错误 数据进行测试。
• 使用 print() 语句来观察程序运行时变量的状态!