2013-04-22 68 views
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编写代码是否是正确的方法?

回答

3

编写一个失败的测试的目的是让每一个测试都是值得的。这只是让你考虑你的测试和你的代码。如果你编写的测试不能开始,然后只有足够的代码来通过测试,那么你知道你编码的所有东西都是必须的,并为你的应用程序增加了价值。例如,以最纯粹的形式使用TDD,对于上述场景,如果您希望第一次测试测试方法是否在一个日期接近另一个时返回true,则可以编写测试来声明true和刚才设置的方法

bool Validate(Condition condition) 
{ 
    return true; 
} 

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

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

这意味着你写代码的每一位有必要,你知道,当你希望它它的行为完全。这也可以让您将问题分解成几个步骤,并逐个处理每个阶段。据我了解,这就是TDD的全部内容。

+0

有关此问题的思考,我意识到,我违反写作“刚刚够”的原则,走了一步,没有真正思考它。在我写任何其他测试之前,'return true;'应该已经被单元测试覆盖了。虽然这个例子已经完成,但我不止一次遇到过类似的问题。在编写测试时,我会尽量多注意哪些代码是正确的。我相信,在我的例子情况下,即使测试会通过,我还是应该把它写,否则'返回true;'不包括在内。 – 2013-04-22 16:49:23

1

红色/绿色/重构的想法是,当你编写测试时,它不应该通过,因为功能尚不存在。这是测试的要求,引导你编写通过的实现。

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

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

而且不要忘了更多的测试。你有什么要求? StartDate可以为空吗?一个任务可能需要超过一天少,所以可以在结束日期和开始日期是一样的吗?但是,如果你比较分钟和秒,也暗示这些真的是DateTime和不只是日期,而不应因此它们被命名的startDateTime/EndDateTime?

我们的目标不只是生产工作的软件。目标是编写可读,可理解,清晰的软件。该软件应该作为自己的文档。 TDD可以通过提出正确的问题来帮助您。