编写不会先失败的测试

时间:2013-04-22 15:18:07

标签: unit-testing tdd

TDD最佳实践表明,新的测试应该失败。但是,我认为有可能需要进行测试,尽管在刚刚编写完成后它不会失败。

示例工作流程:

  1. 写入测试,检查结束日期是否在开始日期之前 - 测试失败;
  2. 编写代码 - 测试通行证;
  3. 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编写代码是否正确?

2 个答案:

答案 0 :(得分:3)

编写失败的测试的重点是每一次测试都是值得的。您只需要考虑测试和代码。如果您编写的测试无法启动,然后只需要足够的代码来使测试通过,那么您就知道您编写的所有内容都是必要的,并为您的应用程序增加了价值。

例如,对于上面的场景,以最纯粹的形式使用TDD,如果你想要第一个测试来测试方法是否返回true,如果一个日期在另一个之后,你可以编写测试来断言true和just将方法设置为

bool Validate(Condition condition)
{
    return true;
}

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

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

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

答案 1 :(得分:1)

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

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

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

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

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