【问题标题】:Test Cases AND assertion statements测试用例和断言语句
【发布时间】:2008-09-11 09:53:28
【问题描述】:

this question 中的代码让我思考

assert(value>0); //Precondition
if (value>0)
{
  //Doit
}

我从不写 if 语句。断言就足够了/你可以做的。 “早崩溃,经常崩溃”

CodeComplete 状态:

  • 断言语句使应用程序正确
  • if 测试使应用程序健壮

我不认为您通过更正无效输入值或跳过代码使应用程序更健壮:

assert(value >= 0 );  //Precondition
assert(value <= 90);  //Precondition
if(value < 0)         //Just in case
  value = 0;
if (value > 90)       //Just in case
  value = 90;
//Doit

这些更正是基于您对外部世界所做的假设。 只有调用者知道你的函数的“有效输入值”是什么,他必须在调用你的函数之前检查它的有效性。

套用CodeComplete: “当我们完全依赖断言时,现实世界的程序变得太混乱了。”

问题:我是不是错了,固执,愚蠢,太不防备......

【问题讨论】:

  • 我同意你的看法。断言的全部意义在于在测试期间执行完整性检查,这在生产中执行起来过于昂贵。它们的功能与异常有着根本的不同。

标签: defensive-programming


【解决方案1】:

只信任断言的问题在于,它们可能在生产环境中被关闭。引用维基百科的文章:

大多数语言都允许断言 全局启用或禁用,以及 有时独立。断言 通常在开发过程中启用 并在最终测试期间禁用 在发布给客户时。不是 检查断言避免成本 评估断言的同时, 假设断言没有 副作用,仍然产生相同的 正常条件下的结果。在下面 异常情况,禁用 断言检查可能意味着 会中止的程序将 继续运行。这有时是 更可取。 Wikipedia

因此,如果您的代码的正确性依赖于断言的存在,您可能会遇到严重的问题。当然,如果代码在测试期间工作,它应该在生产期间工作......现在进入第二个处理代码并且只是要解决一个小问题的人......

【讨论】:

  • 我认为问题在于解决了一个小问题的人决定在发货前不测试软件。测试阶段不能被明智地“跳过”,因此断言也不能。
【解决方案2】:

使用断言来验证您控制的输入:私有方法等。

使用 if 语句验证您无法控制的输入:为用户使用而设计的公共接口、用户输入测试等。

使用内置断言测试您的应用程序。然后在不使用断言的情况下进行部署。

【讨论】:

    【解决方案3】:

    在某些情况下,断言在构建发布时被禁用。您可能无法对此进行控制(否则,您可以使用断言进行构建),因此这样做可能是个好主意。

    “更正”输入值的问题是调用者不会得到他们期望的结果,这可能导致程序的完全不同部分出现问题甚至崩溃,使调试成为一场噩梦。

    我通常在 if 语句中抛出一个异常来接管断言的角色,以防它们被禁用

    assert(value>0);
    if(value<=0) throw new ArgumentOutOfRangeException("value");
    //do stuff
    

    【讨论】:

    • 我喜欢抛出异常:它总是有效(生产和调试),但为什么还要写断言语句呢?这只适用于“一半”的时间。
    • 我认为这只是一个约定俗成的问题。当我看到一个未捕获的异常时,可能是数以百万计的事情导致了它。当我发现一个失败的断言时,我知道我把自己搞砸了,我更容易找到原因。
    【解决方案4】:

    我不同意这种说法:

    只有调用者知道什么是“有效 输入值”适用于您的功能,并且 他必须在他之前检查它的有效性 调用你的函数。

    调用者可能认为他知道输入值是正确的。只有方法作者知道它应该如何工作。程序员的最佳目标是让客户端陷入“pit of success”。您应该决定在特定情况下哪种行为更合适。在某些情况下不正确的输入值是可以原谅的,在其他情况下你应该抛出异常\返回错误。

    至于断言,我会重复其他评论者,断言是代码作者的调试时间检查,而不是代码客户端。

    【讨论】:

      【解决方案5】:

      不要忘记大多数语言都允许您关闭断言...就个人而言,如果我准备编写 if 测试来防止 所有 范围的无效输入,我不会打扰首先是断言。

      另一方面,如果您不编写逻辑来处理所有情况(可能是因为尝试继续使用无效输入是不明智的),那么我将使用断言语句并采用“早期失败”方法.

      【讨论】:

        【解决方案6】:

        如果我没记错的话是CS课

        前置条件定义了定义函数输出的条件。如果你让你的函数处理错误条件,你的函数是为这些条件定义的,你不需要断言语句。

        所以我同意。通常你不需要两者。

        正如 Rik 所说,如果您在已发布的代码中删除断言,这可能会导致问题。通常我不会这样做,除非在性能关键的地方。

        【讨论】:

        • 这种方法的问题是非法调用导致的崩溃可能发生在程序的完全不同的部分,这使得调试成为一场噩梦。
        • 我同意。我想我的答案不完整。我通常不会删除已发布代码中的断言。我会修正我的答案。
        【解决方案7】:

        我应该说我知道断言(此处)在生产代码中消失的事实。

        如果 if 语句实际上纠正了生产代码中的无效输入数据,这意味着断言在调试代码测试期间从未发生过,这意味着您编写的代码从未执行过。

        对我来说,这是一个 OR 情况:

        (引用 Andrew)“防止所有范围的无效输入,我一开始就不会为断言而烦恼。” -> 编写一个 if 测试。

        (quote aku) “错误的输入值是可以原谅的” -> 写一个断言。

        我都无法忍受...

        【讨论】:

          【解决方案8】:

          对于只有你会使用的内部函数,只使用 asserts。断言将帮助您在测试期间发现错误,但不会影响生产中的性能。

          使用 if-conditions 检查源自外部的输入。在外部,这是您/您的团队控制和测试的代码之外的任何地方。

          或者,您可以同时拥有两者。这适用于在生产之前进行集成测试的面向外部的功能。

          【讨论】:

            【解决方案9】:

            断言的一个问题是它们可以(并且通常会)从代码中编译出来,因此您需要添加两面墙,以防编译器丢弃其中一个。

            【讨论】:

            • 断言从生产代码中删除设计。这是一个功能,而不是一个错误。你只需要适当地使用它们。如果您想在生产代码中进行测试,请不要使用断言。
            猜你喜欢
            • 1970-01-01
            • 2020-10-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-06
            • 1970-01-01
            相关资源
            最近更新 更多