1

TDD 最佳实践表明新的测试应该失败。但是,我认为测试可能是必要的,尽管它在刚刚编写时不会失败。

示例工作流程:

  1. 编写测试以检查结束日期是否早于开始日期 - 测试失败;
  2. 编写代码 - 测试通过;
bool Validate(Condition condition)
{
    if (condition.EndDate <= condition.StartDate)
    {
        return false;
    }

    return true;
}

3. 重构——测试仍然通过。

bool Validate(Condition condition)
{
    return (condition.EndDate > condition.StartDate);
}

在第 3 步之后,我看到如果我没有重构条件,我可以添加一个新测试,如果开始日期早于结束日期,它会检查该方法是否返回 true。但是,如果我先进行重构,那么编写这样的测试将意味着它立即通过。在我看来,测试可能会使代码更加健壮。

根据 TDD,为什么编写这样的测试是一个坏主意/不是一个好主意?

编辑:我现在在想,也许return true;在实现中默认编写可能不是一个好主意,我应该抛出一个NotImplementedException. 根据 TDD 编写代码是否是正确的方法?

4

2 回答 2

3

编写失败的测试的目的是让每一个测试都是值得的。这只是为了让您考虑您的测试和代码。如果您编写的测试开始时失败,然后只编写了足以使测试通过的代码,那么您就知道您编写的所有代码都是必要的,并为您的应用程序增加了价值。

例如,对于上述场景,以最纯粹的形式采用 TDD,如果您希望您的第一个测试测试方法是否在一个日期之后返回 true,您可以编写测试断言 true 并设置方法至

bool Validate(Condition condition)
{
    return true;
}

这将使您的第一次测试通过。然后,如果结束日期早于开始日期,您将编写另一个测试来断言该方法是否失败,这显然会失败。然后,您将编写代码以通过测试,例如:

bool Validate(Condition condition)
{
    return (condition.EndDate > condition.StartDate);
}

这意味着您编写的每一段代码都是必要的,并且您知道它的行为完全符合您的要求。这也允许您将问题分解为多个步骤并一次处理每个阶段。据我了解,这就是 TDD 的全部意义所在。

于 2013-04-22T15:45:02.097 回答
1

Red/Green/Refactor 的想法是,当你编写测试时,它不应该通过,因为功能还不存在。指导您编写通过实现的是测试的要求。

你在这里看到一个非常简单的案例。有经验的 TDD 从业者可能会在编写代码之前查看问题并跳过测试执行步骤,从而节省编译/测试周期的成本。

另一方面,可能还有更多的重构工作要做​​。一件事是名称:验证。验证什么?它有什么作用?应该做多少?重命名它,直到它说出它的作用。接下来,您要对该对象之外的对象进行日期比较。“条件”类是否有责任确保结束日期跟在开始日期之后?或者它真的是一个业务规则,与 Condition 的具体使用相关联?

不要忘记更多的测试。你有什么要求?StartDate 可以为空吗?一项任务可以花不到一天的时间,那么 EndDate 和 StartDate 可以相同吗?但是,如果您也在比较分钟和秒,这意味着它们确实是 DateTime 而不仅仅是日期,因此它们不应该被命名为 StartDateTime / EndDateTime 吗?

目标不仅仅是生产工作软件。目标是编写可读、易懂、清晰的软件。该软件应作为其自己的文档。TDD 可以通过提出正确的问题来帮助您。

于 2013-04-22T16:37:33.957 回答