我想多介绍一下使用断言的技术。
断言使您可以在代码中的任何位置指定您期望为真的内容。在函数的开头,您可以使用断言来确保参数具有合理的值。这些被称为先决条件。而函数结束时,你可以检查以确保你即将返回的内容与函数的目的一致。这些被称为后置条件。在函数的中间,您可以确保任何中间计算都是合理的(尽管您通常应该尝试使您的函数足够小,以便没有很多中间计算)。
使用类,您可以检查以确保将好的值传递给构造函数。在其他方法中,您可以在方法返回之前确保类的一般状态是合理的。这些被称为不变量。
在调试的时候,我通常会发现 bug 很难找到,因为我错过了一些断言,让崩溃离问题的根源越来越远。我使用调试过程来帮助解决这个问题。我从崩溃实际发生的地方开始,然后思考“在这个抽象级别,出了什么问题?”。如果它在函数中间崩溃,我可能会意识到传递给函数的参数不正确,所以我在函数开头附近添加了额外的断言来捕捉这些。当我下次运行它并且它崩溃时,崩溃发生得更快。如果崩溃现在发生在函数的顶部,我会上一层堆栈并询问“为什么调用者没有传递正确的值?”。然后我可能会意识到一些中间计算是错误的,所以我在那里添加了一个断言以便更早地捕获它。中间计算可能是由于另一个函数返回了错误的值,在这种情况下,我将添加一个后置条件断言来更早地捕获它。可能是由于当前函数没有传递正确的参数,所以我在这个函数中添加了一个前置条件断言。
每次我添加一个断言时,我都会让崩溃更接近问题的真正根源。最终我到达了崩溃发生在真正的逻辑错误的地步,并且修复是显而易见的。但是通过这个过程,我也让未来的问题更容易被发现。
在进行单元测试时,您可以应用类似的推理。问“我的测试出了什么问题,导致这个问题没有被更早发现?”