Debug.Assert vs. Specific Thrown Exceptions我刚开始浏览John Robbins的"调试MS .Net 2.0应用程序",并且因为他对Debug.Assert(...)的传福音而感到困惑。 他指出,良好实现的Asserts会在某种程度上存储错误状态,例如:
现在,就个人而言,我似乎很疯狂,他如此喜欢在没有真正明智的"商业逻辑"评论的情况下重申他的考试,也许"因为flobittyjam widgitification过程,我必须永远不会发生i <= 3"。 所以,我认为我认为Asserts是一种低级别的"让我保护我的假设"的东西......假设一个人认为这是一个只需要在调试中做的测试 - 即你保护自己不受同事的影响和未来的程序员,并希望他们实际测试的东西。 但是我没有得到的是,他继续说除了正常的错误处理之外你还应该使用断言;现在我设想的是这样的:
我通过Debug.Assert重复错误条件测试获得了什么?如果我们谈论一个非常重要的计算的仅调试双重检查,我想我会得到它...
...但是我没有得到参数测试,这肯定值得检查(在DEBUG和Release版本中)......或者不是。我错过了什么?
断言不适用于参数检查。应始终进行参数检查(并且精确地根据文档和/或规范中指定的前提条件),并根据需要抛出 断言用于测试"不可能"的情况,即(在程序逻辑中)假设的事情是真的。断言是告诉你这些假设是否因任何原因被破坏。 希望这可以帮助! 断言与异常抛出有沟通方面。 假设我们有一个带有Name属性和ToString方法的User类。 如果ToString是这样实现的:
它表示Name应该永远不会为null,如果是,则User类中存在错误。 如果ToString是这样实现的:
它表示如果Name为null,调用者正在使用ToString,并且应该在调用之前检查它。 两者的实施
如果Name为null,那么User类中会出现bug,但我们还是要处理它。 (用户在打电话之前不需要检查姓名。)我认为这是罗宾斯推荐的那种安全措施。 在提供关于测试问题的调试与断言的指导时,我已经考虑过这个漫长而艰难的过程。 您应该能够使用错误的输入,错误的状态,无效的操作顺序以及任何其他可能的错误条件来测试您的类,并且断言应该永远不会跳闸。每个断言都在检查一些事情应该始终为真,无论输入或计算是什么。 我已经达到了良好的经验法则: 断言不能替代能够正确独立于配置运行的健壮代码。它们是互补的。 在单元测试运行期间,即使在输入无效值或测试错误条件时,断言也不应跳闸。代码应该处理这些条件而不会发生断言。 如果断言跳闸(在单元测试中或在测试期间),则会对该类进行窃听。 对于所有其他错误 - 通常是环境(网络连接丢失)或误用(调用者传递空值) - 使用硬检查和异常会更好,更容易理解。如果发生异常,则调用者知道它可能是他们的错。如果发生断言,则调用者知道它可能是断言所在代码中的错误。 关于重复:我同意。我不明白为什么你会用Debug.Assert和异常检查来复制验证。它不仅会给代码增加一些噪音,而且还会让人感到困惑,因为这是一种重复的形式。 我使用显式检查,在私有方法的公共和受保护方法和断言上抛出异常。 通常,显式检查会保护私有方法无论如何都看不到错误的值。所以,断言正在检查一个应该是不可能的条件。如果一个断言触发,它告诉我在该类的一个公共例程中包含的验证逻辑中存在缺陷。 可以捕获并吞下异常,使错误对测试不可见。 Debug.Assert不会发生这种情况。 没有人应该有一个能够捕获所有异常的捕获处理程序,但无论如何人们都会这样做,有时这是不可避免的。如果您的代码是从COM调用的,则互操作层会捕获所有异常并将其转换为COM错误代码,这意味着您将看不到未处理的异常。断言不会受此影响。 此外,当异常未得到处理时,更好的做法是采取小型转储。 VB比C#更强大的一个领域是,当异常处于运行状态时,您可以使用异常过滤器来捕捉小型转储,并保持其余的异常处理不变。 Gregg Miskelly关于异常过滤器注入的博客文章提供了一种从c#执行此操作的有用方法。 关于资产的另一个注意事项......他们在单元测试代码中的错误条件时表现不佳。有一个包装器来关闭单元测试的断言是值得的。 IMO只是失去了开发时间。正确实施的例外可让您清楚了解发生的情况。我看到太多的应用程序显示模糊的"断言失败:我<10"错误。我认为断言是一种临时解决方案。在我看来,没有断言应该在程序的最终版本中。在我的实践中,我使用断言进行快速和脏检查。代码的最终版本应考虑错误的情况并相应地采取行动。如果发生了不好的事情,你有2个选择:处理它或离开它。如果传入了错误的参数,函数应抛出一个带有意义描述的异常。我认为验证逻辑重复没有任何意义。 很好地使用Assert的示例:
我个人认为只有当你知道某些东西超出了理想的限制时才应该使用Assert,但是你可以确定它是合理安全的。在所有其他情况下(随意指出我没有想到的情况)使用异常来快速失败。 对我来说,关键的权衡是你是想要关闭带有异常的实时/生产系统以避免损坏并使故障排除更容易,或者是否遇到了一个永远不允许在测试/调试版本中继续被忽视的情况但是被允许继续生产(当然记录警告)。
比照http://c2.com/cgi/wiki?FailFast 这是2美分。 我认为最好的方法是使用断言和异常。两个方法之间的主要区别,即imho,如果Assert语句可以从应用程序文本中轻松删除(定义,条件属性......),而抛出的Exception依赖于(tipically)一个更难删除的条件代码(具有预处理器条件的多段)。 每个应用程序异常都应该正确处理,而断言只应在算法开发和测试期间得到满足。
如果将空对象引用作为例程参数传递,并且使用此值,则会得到空指针异常。确实:你为什么要写一个断言?在这种情况下浪费时间。
异常更有用,但它们可能(imho)非常重,无法管理,并且有可能使用太多异常。并且它们需要额外的检查,可能不希望优化代码。 |