在TDD中,在编写空方法之前运行测试的优势是什么?

时间:2009-01-06 19:09:58

标签: visual-studio-2008 unit-testing tdd

我看到很多TDD从业者都遵循这个周期:

  

1)将测试写成目标   对象和API已经存在。

     

2)编译解决方案并查看   打破。

     

3)编写足够的代码来实现它   编译。

     

4)运行测试,看看是否失败。

     

5)编写足够的代码来获取它   通过。

     

6)运行测试并看到它通过

     

7)重构

步骤1和2有什么优势?对于像Visual Studio这样的IDE,这真的很烦人,因为intellisense跳到那里试图猜测不存在的方法和属性。

我通常从第3步开始,让我的所有方法都抛出NotImplementedException,这对我来说似乎很好,但也许我错过了一些东西。

编辑以澄清:这不是一个问题,为什么我会在测试通过之前看到测试失败;从第3步开始,这是完全有道理的。我的问题是为什么甚至在此之前人们会在单元测试中调用API中不存在的方法(因此VS将显示红色波形,或者将整个方法名称描绘为红色等)并尝试编译。对我而言,VS告诉我该方法不存在的事实已经足够了。

14 个答案:

答案 0 :(得分:18)

然后首先编写方法名称来尝试它。通过首先编写测试和方法,我发现它迫使我真正考虑API,并且我可以轻松地更改名称,而不必担心已编写的代码。我的建议是尽量不遵守规则,并监控发生的情况。如果发现它会导致问题,请切换回来。如果没有,你现在就有了一种新的工作方式。

还要记住,当您第一次了解事物时,通常需要一套明确的规则来为您提供背景信息。当您开始从初学者转向更高级时,您将获得更多背景并能够进行调整。这听起来像是你在哪里。

答案 1 :(得分:12)

我是TDD从业者,我认为你做这件事的方式很好。看到测试失败是重要的部分,而不是看到代码无法编译。

尝试将其作为修订序列:

  

1)在a中写下你的测试   评论好像是目标对象和   API已经存在。

     

2)编写足够的API代码   编译。

     

3)取消注释您的测试代码。

     

4)运行测试并看到它失败。

     

5)编写足够的代码来获取它   通过。

     

6)运行测试并看到它通过

     

7)冲洗并重复......

通过这种方式,您仍然可以首先获得思考测试的好处,而不是先实现。

答案 2 :(得分:10)

Eclipse中使用JUnit的工作流(与带有MSTest的Visual Studio相反)是步骤1-3最有意义的地方。然后,第3步就是使用Eclipse的快速修复功能(Ctrl-1)根据您刚刚编写的单元测试生成存根代码。

  

DoesntExistYet someObject = new DoesntExistYet();
  int result = someObject.newMethod(“123”);
  assertEquals(123,result);

第一行的快速修复将自动创建DoesntExistYet类(让你首先通过向导调整它),下一个快速修复将为你创建newMethod,根据你如何使用它来适当地找出签名

因此,通过所有自动化使事情变得更轻松,您可以继续使用人们提到的关于如何使用它来规划API的其他优势。

答案 3 :(得分:10)

我认为每个人都缺少一个关键点 - 你怎么知道所需的方法还不存在?编写一个单元测试,调用一个不应该存在的方法,然后观察它失败,验证你的假设是否正确。在编译语言中,它应该无法编译。在非编译语言中,执行失败可能比检查API快得多。在大多数语言中,继承和多态可能会导致存在未在API的心理模型中注册的方法。

在极少数情况下,您可能会发现该方法确实存在(并且IntelliSense可能也有助于检测该方法),您可能会发现需要更改所需的方法签名。或者,您甚至可能发现根本不需要编写该方法(可能是您上周编写的,但忘了)。

当然,您可以选择跳过前两个步骤,甚至完全免除TDD,但这些步骤确实有目的。尽管如此,我同意一般的观点,即我们总能从任何“最佳实践”中对这些步骤背后的基本原理的更多描述中受益。

编辑:从贾斯汀标准......

  

或者如果您在开发团队中工作并且没有亲自编写代码   你依靠。对于大多数开发人员来说,我认为这是一种相当普遍的情况。

编辑:来自senfo ...

  

如果您在跟踪基础中实施的方法时遇到问题   类,听起来像你的继承层次结构太复杂了。我仍然投票   你了,因为我同意我花更多的时间来验证方法还没有   如果我从单元测试开始就存在。

@senfo:继承层次结构中的复杂性肯定会过多,但这是一个明显解决方案的不同问题。即使您现有的代码是完美的,从单元测试开始尝试调用可能不存在的方法仍然是有价值的,只是为了快速向自己证明它不存在。当然,跳过这一步是可以理解的 - 我可能会在我的测试行为不端的特定情况下回到它(在那种特殊情况下验证我没有调用我刚才写的东西)。

答案 4 :(得分:3)

看到它中断可确保您在测试代码中没有出错,并从一开始就构建了一个工作测试。

此外,尝试“使用”API会让您从不同的角度(API 用户的角度)思考它,这几乎总是有益的。在尝试编写API之前执行此操作非常重要(这将始终从API 设计器的角度来看)。很难解释使用自己的API的价值,但行业术语是dog-fooding

答案 5 :(得分:3)

首先编写测试会强制您决定接口

就是这样。

但这就足够了!接口是您必须在其中编码的框;忽略它们并开始编码,你经常需要重新修改你的工作才能使用它

编辑:我真的应该更仔细地阅读这个问题,OP正在寻找更具体的答案。这是它:省略visual studio中的第2步,而不是存在方法/类。当显然没有必要使用工具时,没有理由对这个扩展的配方迂腐。

答案 6 :(得分:3)

我看到许多回答此问题的人都有Visual Studio背景。我自己使用了VS,并且在TDD的前两个步骤中指出了同样的问题。

如果您使用更强大的代码编辑IDE,就像您在Java(Eclipse,Netbeans,IntelliJ)中所拥有的那样,前两个步骤更有意义。这里提供的快速修复和代码生成工具,使得针对不存在的类或方法编写测试是创建特定类或声明该特定方法的最快方法;您只需按一个按钮,就会为您生成缺少的类或方法。编写方法调用或对象实例化比首先创建类或方法然后使用它们更快。例如,一旦调用了方法,方法名称和参数类型就会给出方法的签名,因此IDE很容易创建它们。这真是一个很棒的过程,我不会以任何其他方式编程。将它与实际使用api之前的优点结合起来,你描述的TDD执行方式很有意义。

我在这里声称的内容在动态语言中也是如此,在IDE中,传统上不会因为缺少类或方法而在IDE中出现任何编译错误。测试将失败,为您提供红色条。

对于Visual Studio用户,如果要共享此体验,请安装Visual Studio的Resharper插件。这将提供许多Java IDE中可用的相同功能。

答案 7 :(得分:2)

请记住,首先,基本周期是红绿重构。因此,代码无法编译根本不是核心TDD周期的一部分。尽管如此,正如几位人士所指出的那样,在构建测试时考虑API是有用的,而这正是您的前两个步骤倾向于自己的步骤。如果您按照希望的方式编写API以使测试变得简单,那么您更有可能成为受测试类的快乐消费者。

答案 8 :(得分:1)

至于Visual Studio对TDD的支持,我同意intellisense有时会妨碍,但你实际上可以使用VS进行TDD,尽管它仍然有限。如果测试方法引用了被测试类上的不存在的方法,则可以通过按Ctrl-K,Ctrl-M让VS为您创建存根。

不幸的是,这对VS2008中的属性不起作用,但据我在VS2010的说明中可以看出,下一版本在这方面有很多改进。

答案 9 :(得分:1)

这里的危险是你在编写第一个测试时预先设定了API。一个诀窍是考虑第一个测试 - 也许在开始编写代码之前将其写在纸上或者至少在VS之外。一旦你知道API需要的方法,你就可以继续第3步,然后回溯(相对于VS)到第1步并编写实际的测试。

我承认我通常会在脑海中完成大部分工作,并从步骤(3)开始。

答案 10 :(得分:1)

我认为使用像Resharper这样的工具可以帮助您更好地感受TDD。它确实对我有用。

这是因为它可以自动生成许多在编写时需要存根的空类/方法。当您考虑如何运行测试以及您正在测试的类/方法应该如何操作时,这有助于不中断您的流程。

答案 11 :(得分:1)

这不是本书的测试驱动开发。如Beck的“测试驱动开发:通过示例”中所述的"official" TDD process如下:

  • 快速添加测试
  • 运行所有测试并看到新的失败
  • 进行更改
  • 运行测试并查看所有成功
  • 重构以删除重复

答案 12 :(得分:1)

就我而言,“看到一个红色的波浪”==编译器失败了。请记住,原始的单元测试/ TDD宣言是在没有IDE的情况下编写的。好的IDE在当时的java世界中非常罕见,并且正如其他人所指出的那样,动态语言仍无法确定在编译时,句点不存在方法。

如果您使用的语言/ IDE组合会立即显示编译错误,那么这将被视为编译周期失败。

答案 13 :(得分:0)

我同意其他受访者的看法,我认为只是那些天真地试图不假思索地做“正确的事”的人。在你编写任何代码之前,他们听说过你应该编写测试的地方,他们会按字面意思编写并尝试编译。

这与this answer to another question有关,先用你的头!这是最好的最佳做法。