【问题标题】:In TDD, what is the advantage of running the tests before even writing an empty method?在 TDD 中,在编写空方法之前运行测试有什么好处?
【发布时间】:2009-01-06 19:09:58
【问题描述】:

我看到很多 TDD 实践者遵循这个周期:

1) 像目标一样编写测试 对象和 API 已经存在。

2) 编译解决方案并查看 休息。

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

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

5) 编写足够的代码来实现 经过。

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

7) 重构

第 1 步和第 2 步的优势是什么?对于像 Visual Studio 这样的 IDE,这样做真的很烦人,因为智能感知会到处乱跳,试图猜测不存在的方法和属性。

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

编辑澄清:这不是为什么我应该在测试通过之前看到测试失败的问题;这将在第 3 步之后介绍,而且完全有道理。我的问题是,为什么在此之前人们会调用 API 中不存在的单元测试方法(因此 VS 会显示红色曲线,或将整个方法名称涂成红色等)并尝试编译。对我来说,VS 告诉我该方法不存在这一事实已经足够了。

【问题讨论】:

  • 您说只使用“第 3 步开始”,但您在第 1 步中编写测试。如果从第 3 步开始,您什么时候编写测试?请澄清。
  • 当我说“编写足够的代码”时,这意味着在具有 NotImplementedException 的类中编写方法,然后编写测试。它编译并测试失败,但出现上述异常。

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


【解决方案1】:

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

还请记住,当您第一次学习事物时,通常需要一套清晰的规则来为您提供上下文。当您开始从初学者转向更高级时,您将获得更多上下文并能够进行调整。在我看来,这就是你所在的地方。

【讨论】:

    【解决方案2】:

    我是一名 TDD 实践者,我认为您的做法很好。看到测试失败是重要的部分,而不是看到代码无法编译。

    试试这个作为修改后的序列:

    1) 在内编写您的测试 评论就像目标对象和 API 已经存在。

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

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

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

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

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

    7) 冲洗并重复...

    这样您仍然可以从思考先测试而不是先实施来获得好处。

    【讨论】:

    • 我同意,除了看到代码无法编译(或以非编译语言执行)是有价值的,正如我在回答中所描述的那样。
    • 我读了你的回答,你说得有道理。为了减轻这种担忧,您可以在上面添加步骤 (1.5):“取消注释您的代码并验证哪些 api 方法已经存在。”
    【解决方案3】:

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

    DoesntExistYet someObject = new DontExistYet();
    int 结果 = someObject.newMethod("123");
    assertEquals(123, 结果);

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

    因此,所有这些自动化使事情变得更容易,然后您将继续了解人们提到的其他优势,即能够通过您将如何使用它来指定您的 API。

    【讨论】:

    • 同意。 Eclipse 中的快速修复和代码生成,再加上在编写 API 之前对其进行思考,使之成为一种简洁而强大的 TDD 方法。
    【解决方案4】:

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

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

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

    编辑:来自贾斯汀标准...

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

    编辑:来自 senfo...

    如果您在跟踪 base 中实现了哪些方法时遇到问题 类,在我看来你的继承层次结构太复杂了。我还是投了 你起来,因为我同意我需要更多时间来验证一个方法还没有 如果我从单元测试开始,则存在。

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

    【讨论】:

    • 我明白你的意思,但是你不小心写出与现有隐藏方法相同的方法签名的可能性很低。如果名称有任何变化,则现有方法将不明显。 Intelisense 可能会有所帮助,但最终只有熟悉代码才有用。
    • 实际上,我发现这种可能性很高——我倾向于与我的命名非常一致,或者我发现自己编写了一个已经存在但我认为我必须提供的通用方法。当然,如果您已经离开代码一段时间(回到旧项目),这更有可能发生。
    • 或者,如果您在一个开发团队中工作并且没有亲自编写您所依赖的代码。我认为这对大多数开发人员来说是相当普遍的情况。
    • 如果您在跟踪基类中实现了哪些方法时遇到问题,我觉得您的继承层次结构太复杂了。我仍然投票给你,因为我同意如果我从单元测试开始,我会花更多时间来验证一个方法是否不存在。
    【解决方案5】:

    首先编写测试会迫使您决定接口

    仅此而已。

    但这已经足够了!接口是您必须在其中编码的盒子;忽略它们并开始编码,并且您通常必须在使用之前返工工作

    编辑:我真的应该更仔细地阅读这个问题,OP 正在寻找更具体的答案。就是这样:在 Visual Studio 中省略第 2 步,取而代之的是存根方法/类。当一个人使用的工具显然没有必要时,没有理由对遵循这个扩展配方感到迂腐。

    【讨论】:

      【解决方案6】:

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

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

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

      对于 Visual Studio 用户,如果您想分享这种体验,请安装适用于 Visual Studio 的 Resharper 插件。这将提供许多与 Java IDE 相同的功能。

      【讨论】:

      • +1 - 我使用 resharper,它允许我创建不存在的方法。使得首先在 vs.net 上编写测试是可以容忍的。 :)
      【解决方案7】:

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

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

      【讨论】:

      • 谢谢,但这不是我的问题。您提到的内容将在第 3 步之后介绍,并且在 TDD 中肯定是强制性的。
      • @rodv:狗食会改变你编写代码的方式,我相信这就是(其中一个原因)TDD 提倡将测试作为第一件事的原因。
      【解决方案8】:

      请记住,首先,基本循环是红-绿-重构。因此,代码无法编译根本不是核心 TDD 循环的一部分。话虽如此,正如一些人所指出的那样,根据正在构建的测试来考虑 API 是很有用的,这就是您的前两个步骤往往会发挥作用的地方。如果您按照自己希望的方式编写 API 以简化测试,那么您更有可能成为被测类的快乐消费者。

      【讨论】:

        【解决方案9】:

        关于 Visual Studio 对 TDD 的支持,我同意智能感知有时会妨碍您,但是您实际上可以将 VS 用于 TDD,尽管它仍然有些限制。如果测试方法引用了被测类上不存在的方法,您可以让 VS 通过按 Ctrl-K、Ctrl-M 为您创建一个存根。

        不幸的是,这不适用于 VS2008 中的属性,但据我所知,在 VS2010 的注释中,下一个版本在这方面有很多改进。

        【讨论】:

        • 您的第一段已在第 3 步开始介绍,所以这不是我要求的。请参阅我的编辑以进行澄清。不过,关于创建存根的提示非常好,这使得步骤 1-2 与 Cory Foy 的回答一起更有意义。
        【解决方案10】:

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

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

        【讨论】:

          【解决方案11】:

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

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

          【讨论】:

            【解决方案12】:

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

            • 快速添加测试
            • 运行所有测试并查看新的失败
            • 进行一点改变
            • 运行测试并看到它们全部成功
            • 重构以删除重复

            【讨论】:

              【解决方案13】:

              就我而言“看到红色曲线”== 编译器失败。请记住,最初的单元测试/TDD 宣言是在没有考虑 IDE 的情况下编写的。好的 IDE 在当时的 Java 世界中非常罕见,正如其他人所指出的那样,动态语言仍然无法确定方法在编译时不存在。

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

              【讨论】:

                【解决方案14】:

                我同意其他受访者的观点,我认为这只是天真地试图不假思索地做“正确的事情”的人。他们在某处听说您应该在编写任何代码之前编写测试,他们确实这样做并出于某种原因尝试编译。

                这和this answer to another question有关,先动动脑子!这是最佳实践。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-09-19
                  • 2020-03-04
                  相关资源
                  最近更新 更多