【问题标题】:Unit testing specific values单元测试特定值
【发布时间】:2010-08-15 04:53:27
【问题描述】:

考虑以下代码(根据要求 3 出于某种原因是特殊的):

bool IsSpecial(int value)
   if (value == 3)
      return true
   else
      return false

我将使用几个函数对此进行单元测试 - 一个名为 TEST(3IsSpecial) 的函数断言,当传递 3 时,该函数返回 true,另一个传递除 3 之外的某个随机值并断言该函数返回 false。

当需求发生变化并说它现在变为 3 并且 20 是特殊的时,我会编写另一个测试来验证当使用 20 调用此函数时也返回 true。该测试会失败,然后我会去更新函数中的 if 条件。

现在,如果我的团队中有些人不相信单元测试并且他们做出了这种改变怎么办。他们将直接去更改代码,因为我的第二个单元测试可能不会测试 20(它可能是随机选择一个 int 或有一些其他 int 硬编码)。现在我的测试与代码不同步。我如何确保当他们更改代码时某些单元测试或另一个失败?

我在这里可能做错了什么,所以也欢迎任何其他技术来解决这个问题。

【问题讨论】:

    标签: unit-testing tdd


    【解决方案1】:

    这是个好问题。正如您所注意到的,Not3IsNotSpecial 测试选择一个随机的非 3 值将是传统方法。这不会改变“特殊”的定义。

    在 .NET 环境中,您可以使用新的代码协定功能直接在方法中编写测试谓词(后置条件)。静态分析器会捕捉到您提出的缺陷。例如:

    Contract.Ensures(value != 3 && Contract.Result<Boolean>() == false);
    

    我认为任何 TDD 爱好者现在都在尝试使用合约来了解使用模式。您拥有证明正确性的工具的想法非常强大。您甚至可以为接口指定这些谓词。

    我见过的唯一可以解决这个问题的测试方法是Model Based Testing。这个想法类似于合同方法。您抽象地设置 Not3IsNotSpecial 条件(例如,IsSpecial(x =&gt; x != 3) == false))并让模型执行环境生成具体测试。我不确定,但我认为这些环境也可以进行静态分析。无论如何,您让模型执行环境针对您的 SUT 连续运行。我从未使用过这样的环境,但这个概念很有趣。

    【讨论】:

      【解决方案2】:

      不幸的是,这种特定情况是难以防范的。使用 IsSpecial 之类的函数,测试所有 40 亿个负测试用例是不现实的,所以,不,您并没有做严重的错误。

      这就是我的想法。许多存储库都有钩子,允许您在每次签入时运行一些进程,例如运行单元测试。可以设置一个标准,新签入的代码必须在单元测试下达到代码覆盖率的某个阈值。如果提交不符合某些指标,则会被拒绝。

      我从来没有设置过这些系统之一,所以我不知道涉及什么,但我知道这是可能的。

      相信我,我能感受到你的痛苦。我与同样反对单元测试的人一起工作。

      【讨论】:

        【解决方案3】:

        您需要考虑的一件事是为什么 3 是特殊字符而其他字符不是。如果它定义了您的应用程序的某些方面,您可以取出该方面并从中进行枚举。

        现在您可以在此处检查,如果枚举中不存在值,则此测试应该失败。并为枚举类编写一个测试以检查可能的值。如果添加了新的可能值,您的测试应该会失败。

        所以你的方法会变成:

        bool IsSpecial(int value)
           if (SpecialValues.has(value))
              return true
           else
              return false
        

        您的 SpecialValues 将是一个枚举,例如:

        enum SpecialValues {
        

        三(3),二十(20)

           public int value;
        }
        

        现在你应该写来测试枚举的可能值。一个简单的测试可以是检查可能值的总数,另一个测试可以是检查可能值本身

        【讨论】:

        • 如果我在 C++ 中,则无法枚举 SpecialValues 并检查 SpecialValues.has(3) 或 SpecialValues.has(20)。那么问题就来了,对吧?
        • 我不确定这一点,但你能不能遍历 C++ 中的值。如果是,那么您可以在 IsSpecial 中实现功能。
        【解决方案4】:

        要说明的另一点是,在一个不太人为的例子中:

        • 20 可能是基于业务领域知识进行测试的一些有效条件。基于对业务问题的了解以 BDD 风格编写测试可能会帮助您明确地抓住它。

        • 4 可能是一个很好的测试值,因为它是一个边界条件。这在现实世界中可能更有可能发生变化,因此更有可能出现在完整的测试用例中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-25
          • 1970-01-01
          • 2018-11-03
          • 1970-01-01
          • 2020-06-25
          • 1970-01-01
          • 2018-06-11
          • 1970-01-01
          相关资源
          最近更新 更多