【问题标题】:Number of test-cases for a boolean function布尔函数的测试用例数
【发布时间】:2017-09-17 20:37:37
【问题描述】:

我对用于布尔函数的测试用例数量感到困惑。假设我正在编写一个函数来检查某物的售价是否超过 60 美元。

function checkSalePrice(price) {
  return (price > 60)
}

在我的大学预修课程中,他们要求最少的测试包括边界值。因此,在这种情况下,示例测试集是 [30, 60, 90]。我正在学习的这门课程说只测试两个值,更低和更高,例如 (30, 90)

哪个是正确的? (我知道这是在思考一杯水的深度,但由于我是编程新手,所以我想再获得一些样本)

【问题讨论】:

  • 不相关:我认为checkSalePrice() 是一个误导方法名称。当此方法返回 true 或可能返回 false 时,这意味着什么。价格是“检查”的?还是“未经检查”?从这个意义上说,像isSalesPricesBelowThreshold() 这样的名称或类似名称会更加明确。因为这会告诉您 A) 方法是关于什么的,以及 B) 期望得到什么结果。例如,许多人使用非正式标准,例如“名为 checkWhatever 的方法不会返回值,但在未给出检查条件的情况下会抛出异常”。

标签: unit-testing testing tdd


【解决方案1】:

Kent Beck 写了

我是通过有效的代码而不是测试获得报酬,因此我的理念是尽可能少地进行测试以达到给定的信心水平(我怀疑这种信心水平与行业标准相比很高,但这可能只是狂妄自大)。如果我通常不会犯某种错误(例如在构造函数中设置错误的变量),我不会对其进行测试。我确实倾向于理解测试错误,所以当我有复杂条件的逻辑时我会格外小心。在团队中编码时,我会修改策略以仔细测试我们共同容易出错的代码。

我?我犯了栅栏帖子错误。所以我绝对想确保我的测试套件能够捕捉到checkSalePrice的以下错误实现

function checkSalePrice(price) {
    return (price >= 60)
}

如果我使用测试驱动开发来编写 checkSalePrice,那么我希望通过确保测试在我通过测试之前失败来校准我的测试。由于在我的编程环境中,一个微不足道的布尔函数返回 false,我的流程看起来像

assert checkSalePrice(61)

这会失败,因为该方法默认返回 false。然后我会实施

function checkSalePrice(price) {
    return true
}

现在我的第一次检查通过了,所以我知道这个边界情况被正确覆盖了。然后我会添加一张新支票

assert ! checkSalePrice(60)

这会失败。提供正确的实现将通过检查,现在我可以自信地根据需要重构该方法。

在此处为任意值添加第三次检查不会在更改代码时提供额外的安全性,也不会让下一个维护者的生活变得更轻松,所以我会在这里解决两种情况。

请注意,我使用的启发式与返回值的复杂性无关,而是方法的complexity

谓词的复杂性可能包括涵盖读取输入的各种问题。例如,如果我们传递一个集合,我们要确保涵盖哪些情况? J. B. Rainsberger建议以下助记符

  1. 一个
  2. 很多
  3. 很多
  4. 哎呀

Bruce Dawson 指出只有 40 亿个浮点数,所以也许你应该[全部测试]。

但请注意,额外的 40 亿减去两次检查并没有增加很多设计价值,因此我们可能已经从 TDD 跨入了不同的领域。

【讨论】:

  • 非常好的答案,虽然我认为“测试 40 亿个值”比“耸肩”有更好的答案......请参阅我的答案。
  • 如果您遵循 TDD 的第三条规则(即您不得编写任何足以通过一个失败的单元测试的生产代码),那么一个或还需要两个测试用例,因为为了满足第二步,assert that checkSalePrice(60) is false 我可以/将写return price == 60 ? false : true
【解决方案2】:

您偶然发现了一般测试的大问题 - 有多少测试足够?!

基本上有三种看待这个的方式:

  • 黑盒测试:您不关心 MuT(被测方法)的内部结构。您关注方法的契约。在您的情况下:price > 60 时应返回 true。当您考虑这一点时,您会发现测试 30 和 90 ... 以及 也许 60。测试角落案例始终是一种很好的做法。所以答案是:3
  • 白盒测试:您对您的测试进行覆盖 测量 - 例如,您努力至少点击一次所有路径。在这种情况下,您可以选择 30 和 90 - 这将导致 100% 的覆盖率:所以这里的答案是:2
  • 随机测试,由QuickCheck 指导。这种方法非常不同:您根本不指定测试用例。相反,您退后一步并确定应该适用于您的 MuT 的规则。然后 framework 创建随机输入并使用它调用你的 MuT - 试图找到上述规则 break 的示例。

在您的情况下,这样的规则可能是:when checkSalePrice(a) and checkSalePrice(b) then checkSalePrice(a+b)。这种方法一开始感觉很不寻常,但是一旦开始探索它的可能性,你就会在其中发现非常有趣的东西。尤其是当您了解您的 代码可以为框架提供所需的“创建者”功能时。这使您可以使用这种方法来测试更复杂的“面向对象”的东西。很高兴看到框架发现缺陷 - 然后意识到框架甚至会找到破坏您指定的规则所需的“最小”示例数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 2020-04-23
    相关资源
    最近更新 更多