示例工作流程:
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编写代码是否正确?
答案 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可以通过提出正确的问题来帮助您。