测试、报错与逐步调试
- 为小函数编写正常与边界测试
- 从错误类型和位置寻找最小修复
运行一次没有报错还不够
晨光书架的合计函数处理十二和八得到二十,看起来成功,但你还不知道空列表、零分钟、负数和文本输入怎样处理。测试是在明确输入下比较实际结果与预期结果。它不能证明所有可能输入都正确,却能覆盖已经想到的重要情况,并在改代码后发现旧行为是否被破坏。测试应该先有预期,再看程序输出,不能运行出什么就把什么写成正确答案。预期来自任务规则与独立计算,不来自模型的自我评价。
选择有代表性的案例
正常案例检验主要功能,例如十二加八等于二十。边界案例检验零、空列表以及门槛附近的数据。错误案例检验明确不接受的输入,例如负分钟。对当前小函数,少量有意义的测试比大量重复同一种正常输入更好。测试数据只用虚构数字与书名,不读取真实参与者记录。不要把执行成功与业务成功混为一谈:程序可能顺利跑完,却漏掉一条记录或用了错误合计规则。
标准库测试示范
import unittest
def total_minutes(values):
if any(type(x) is not int or x < 0 for x in values):
raise ValueError("分钟必须是非负整数")
return sum(values)
class TestMinutes(unittest.TestCase):
def test_normal(self):
self.assertEqual(total_minutes([12, 8]), 20)
def test_empty(self):
self.assertEqual(total_minutes([]), 0)
def test_negative(self):
with self.assertRaises(ValueError):
total_minutes([-1])
if __name__ == "__main__":
unittest.main()- 第一行导入标准库测试工具。
- 第二行定义待测试合计函数。
- 第三行逐项检查,any表示只要有一项非法就成立。
- 第四行在非法情况下抛出值错误。
- 第五行返回合法列表合计。
- 第六行建立一组测试,继承标准库提供的测试基类。
- 第七行定义正常案例。
- 第八行断言实际合计等于二十。
- 第九行定义空列表案例。
- 第十行断言空列表返回零。
- 第十一行定义负数案例。
- 第十二行声明接下来的调用应该抛出指定异常。
- 第十三行提供负数输入触发检查。
- 第十四行判断当前文件是否被直接运行。
- 第十五行直接运行时启动测试,不连接外部服务。
读报错要从近处开始
错误追踪通常包含文件、行号和错误类型。先看最后的类型与说明,再回到相关行和输入。语法错误往往是引号、冒号或缩进问题;值错误通常说明输入不合约定;断言失败说明实际结果与预期不一致。不要一次改十处代码,也不要先删除测试来让结果变绿。建立能复现问题的最小输入,只修改直接原因,然后重跑全部测试,能减少凭感觉修补带来的新问题。
AI辅助调试的边界
可以向AI提供最小代码、虚构输入、实际错误和预期结果,请它解释差异,但不要提交包含密码或私人路径的完整日志。它给出的修复仍需逐行理解与测试,不应直接执行陌生命令。测试通过只说明当前案例符合预期;若规则本身写错,测试也可能同时错误。因此保留独立的题意说明与计算依据,让测试验证程序,而不是让程序反过来定义正确答案。
本节要点
- 测试预期应在运行前依据规则确定
- 正常、边界与错误案例各有作用
- 修复直接原因后重跑测试,不删测试掩盖问题
动手练习:新增零分钟与文本输入测试
- 预测零与十二组成列表的合计
- 给文本十二写一个应该抛出ValueError的错误测试
- 说明如果测试失败,应先看什么而不是直接删除测试
自查清单
- 零分钟结果与文本拒绝预期正确
- 调试步骤包含复现、最小修复与回归
先自己做,再查看参考答案
零与十二的合计应为十二,零属于合法非负整数。文本十二不属于普通整数,因此应使用assertRaises检查调用是否抛出ValueError。若测试失败,先看失败的是结果比较还是预期异常,再核对输入、规则与相关代码行。比如函数忘记类型校验,就应补回类型边界,而不是把错误测试删除或把预期改成实际输出。修改后应重跑正常、空、负数、零和文本案例,检查旧行为有没有被破坏。测试结果只覆盖这些输入,不能宣称所有数据都已正确;若需要AI解释错误,应提供最小且无敏感信息的代码与日志片段。