【问题标题】:Beginning TDD - Challenges? Solutions? Recommendations? [closed]开始 TDD - 挑战?解决方案?建议? [关闭]
【发布时间】:2010-09-06 16:48:49
【问题描述】:

好的,我知道已经有关于getting started with TDD 的问题了。但是,我想我大概知道一般的共识是就这样做,但是,我似乎有以下几点进入游戏时遇到问题:

  • 在使用集合时,即使在基于泛型等我们“知道”它会起作用的情况下,是否仍会测试明显的添加/删除/插入是否成功?
  • 有些测试似乎需要很长时间才能实现。例如,在处理字符串输出时,有没有“更好”的方法来处理这类事情? (例如,在解析之前测试对象模型,将解析分解为小操作并在那里进行测试)在我看来,您应该始终测试“最终结果”,但这可能会有很大差异并且设置起来很乏味。
  • 我没有要使用的测试框架(工作不会为一个框架付费),所以我可以“练习”更多。有什么好的可以免费用于商业用途的吗? (目前我正在使用良好的 'ol Debug.Assert :)
  • 可能是最大的..有时我不知道会发生什么不会。我的意思是,你得到了绿灯,但我总是担心我可能会错过一次测试。 . 你是更深入地挖掘代码来尝试破解代码,还是让它留在原地等待它以后全部崩溃(这将花费更多)..

所以基本上我在这里寻找的不是“做它”,而是更多“我做了这个,遇到了问题,通过这个解决了它们” .. 个人体验:)

【问题讨论】:

    标签: unit-testing language-agnostic tdd


    【解决方案1】:

    根据我自己的经验:

    1. 只测试您自己的代码,而不是底层框架的代码。因此,如果您使用的是通用列表,则无需测试添加、删除等。

    2. 没有2。看那边!猴子!!!

    3. NUnit 是要走的路。

    4. 你绝对不能测试每一个结果。我测试我期望发生的事情,然后测试一些我期望得到异常或无效响应的边缘情况。如果由于您忘记测试而导致出现错误,您应该做的第一件事(在尝试修复错误之前)是编写测试以证明错误存在。

    【讨论】:

    • #3 与语言无关,对于不使用 C# 的人来说也不是很丰富。
    • @Andrew NUnit 绝对与语言无关。您可以使用 C#、VB.NET、F#、Boo、Delphi、Cobol ...... CLR 上的任何内容进行编码。也许您的意思是“平台不可知论”?无论如何,它不仅限于 C#。
    • Ruby(除了 IronRuby)是否使用 CLR?
    • 不,只是 IronRuby(它明确是 Ruby 的 CLR 版本)。
    【解决方案2】:

    无论如何,我都不是 TDD 专家,但这是我的观点:

    • 如果它完全是微不足道的(getter/setter 等),请不要对其进行测试,除非您出于某种原因对代码没有信心。
    • 如果它是一个非常简单但不重要的方法,请对其进行测试。无论如何,测试可能很容易编写。
    • 当谈到预期不会发生的事情时,我想说如果某个潜在问题是您正在测试的类的责任,您需要测试它是否正确处理它。如果不是当前班级的责任,请不要测试。

    xUnit 测试框架通常可以免费使用,因此如果您是 .Net 专家,请查看 NUnit,如果您喜欢 Java,请查看 JUnit。

    【讨论】:

      【解决方案3】:

      我对此的看法如下:

      • +1 表示不测试框架代码,但您可能仍需要测试从框架类派生的类。
      • 如果某些类/方法测试起来很麻烦,则可能强烈表明设计有问题。我尽量遵循“1类 - 1责任,1方法 - 1行动”的原则。这样一来,您就可以更轻松地测试复杂的方法,只需以较小的部分进行测试。
      • +1 用于 xUnit。对于 Java,您也可以考虑 TestNG
      • TDD 不是单一事件,它是一个进程。因此,不要试图从一开始就设想一切,而是要确保在代码中发现的每个错误都在发现后真正被测试覆盖。

      【讨论】:

        【解决方案4】:

        上面的建议很好,如果你想要一个免费框架的列表,你只需要看看*上的xUnit Frameworks List。希望这会有所帮助:)

        【讨论】:

          【解决方案5】:

          我认为 TDD 最重要的事情(实际上也是以某种递归方式的伟大成果之一)是成功管理依赖项。您必须确保模块是独立测试的,不需要复杂的设置。例如,如果您正在测试最终发送电子邮件的组件,请将电子邮件发件人设置为依赖项,以便您可以在测试中模拟它。 这就引出了第二点——模拟是你的朋友。熟悉模拟框架和它们提倡的测试风格(行为,而不是基于经典状态的测试),以及它们鼓励的设计选择("Tell, don't ask" 原则)。

          【讨论】:

            【解决方案6】:

            在我看来(您的里程可能会有所不同):

            1- 如果您没有编写它,请不要测试它。如果您编写了它并且没有对其进行测试,则它不存在。

            3- 正如大家所说,xUnit 是免费的,而且很棒。

            2 & 4- 确切地决定要测试什么是您可以永远与自己辩论的事情之一。我尝试使用按合同设计的原则来划定这条线。有关详细信息,请查看“面向对象的软件构建”或“实用程序员”。

            【讨论】:

              【解决方案7】:

              我发现Three Index Cards to Easily Remember the Essence of TDD 中说明的原则是一个很好的指南。

              无论如何,回答你的问题

              1. 您不必测试您“知道”会起作用的东西,除非您编写了它。你没有写泛型,微软做到了;)
              2. 如果您需要为测试做这么多,可能是您的对象/方法做的太多了。
              3. 下载 TestDriven.NET 以立即在您的 Visual Studio 上开始单元测试(除非是 Express 版本)
              4. 只需测试将会发生的正确事情。您需要测试所有可能出错的地方:您必须等待测试失败。

              说真的,做吧,伙计。 :)

              【讨论】:

              • #1 应该让人放心?? (我知道 - 选择没有损坏)
              【解决方案8】:

              首先,当您第一次尝试在您的编码风格中使用 TDD 时感到沮丧是正常且正常的。只是不要气馁和退出,你需要给它一些时间。这是我们思考如何用代码解决问题的一个重大范式转变。我喜欢把它想象成我们从过程编程转向面向对象编程。

              其次,我认为测试驱动开发首先是一种设计活动,用于通过创建一个测试来充实组件的设计,该测试首先描述它将公开的 API 以及您将如何使用它的功能。测试将帮助塑造和塑造被测系统,直到您能够封装足够的功能来满足您正在处理的任何任务。

              记住以上段落,让我们看看你的问题:

              1. 如果我在我的测试系统中使用一个集合,那么我将设置一个期望以确保调用代码来插入项目,然后断言集合的计数。我不一定要在我的内部列表中测试 Add 方法。我只是确保在调用添加项目的方法时调用它。为此,我在测试框架中添加了一个模拟框架。
              2. 测试字符串作为输出可能很乏味。你不能解释每一个结果。您只能根据被测系统的功能测试您期望的内容。您应该始终将您的测试分解为它正在测试的最小元素。这意味着您将进行大量测试,但测试小而快,只测试它们应该测试的内容,没有别的。
              3. 有很多开源测试框架可供选择。我不会争论哪个是最好的。只需找到您喜欢的并开始使用它。
              4. 您所能做的就是设置您的测试来说明您想要发生的事情。如果出现在您的功能中引入错误的场景,至少您有一个围绕该功能的测试以将该场景添加到测试中,然后更改您的功能直到测试通过。找到我们可能错过测试的一种方法是使用code coverage

              我在第一个问题的答案中向您介绍了嘲弄术语。当您在 TDD 的武器库中引入模拟时,它极大地使测试更容易抽象出不属于被测系统的部分。以下是有关模拟框架的一些资源:

              除了阅读过程之外,帮助使用 TDD 的一种方法是观察人们的做法。我建议在DNRTV 上观看 JP Boodhoo 的屏幕投射。看看这些:

              好的,这些将帮助您了解我介绍的术语是如何使用的。它还将介绍另一个名为Resharper 的工具以及它如何促进TDD 流程。在做 TDD 时,我不能推荐这个工具。好像你正在学习这个过程,你只是发现了一些已经用其他工具解决的问题。

              如果我不通过在Test Driven Development on Pragmatic Programmer 上添加 Kent Beck 的新系列来更新此内容,我认为我会对社区造成不公。

              【讨论】:

              • 戴尔,该死的真棒回答伙伴!非常清楚和肯定,感谢您花时间写一个非常好的答案。明显的赢家! ;)
              • 很好的答案 - 我无法让 JPB 网站上的视频正常工作(http 下载或 silverlight 播放器)。还有其他地方可以托管这些吗?
              • 视频来自 dnrTV。下载后您可能需要 camtasia 视频编解码器才能查看它们。你可以在这里找到它:perseus.franklins.net/tscc.exe
              • 你可能想看看这个 BDD 测试框架:nspec.org
              【解决方案9】:

              保持测试简短,“原子”。在每个测试中测试最小的假设。使每个 TestMethod 独立,对于集成测试,我什至为每个方法创建一个新数据库。如果您需要为每个测试构建一些数据,请使用“Init”方法。使用模拟将您的测试类与其依赖项隔离开来。

              我总是想“我需要编写的最少代码量是多少才能证明这适用于所有情况?”

              【讨论】:

                【解决方案10】:

                在过去的一年里,我越来越相信 TDD 的好处。 我一路上学到的东西: 1)依赖注入是你的朋友。我不是在谈论控制容器和框架的反转来组装插件架构,只是将依赖项传递给被测对象的构造函数。这为代码的可测试性带来了巨大的回报。 2)我带着转换者的热情/*出发,抓住了一个模拟框架,开始尽我所能使用模拟。这导致了脆弱的测试,需要大量痛苦的设置,并且一旦我开始任何重构就会失败。使用正确的测试替身。伪造你只需要尊重一个接口,存根将数据反馈给被测对象,只模拟你关心交互的地方。 3)测试应该很小。目标是在每个测试中测试一个断言或交互。我尝试这样做,而且大部分时间我都在那里。这关乎测试代码的健壮性,以及当您需要稍后重新访问测试时的复杂程度。

                我在使用 TDD 时遇到的最大问题是使用来自标准机构的规范以及该标准的第三方实现,即事实上的标准。我按照规范的字母编写了许多非常好的单元测试,只是发现围栏另一边的实现将标准视为更多的咨询文档。他们玩得很松。解决此问题的唯一方法是使用实​​现和单元测试进行测试,并根据需要重构测试和代码。真正的问题是我相信只要我有代码和单元测试一切都很好。不是这样。您需要在进行单元测试的同时构建实际输出并执行功能测试。在整个过程中的小部分利益 - 到用户或利益相关者手中。

                【讨论】:

                  【解决方案11】:

                  除此之外,我想我会说我已经提出了blog post 我对开始测试的想法(在此讨论和我自己的研究之后),因为它可能对查看此内容的人有用线程。

                  "TDD – Getting Started with Test-Driven Development" - 到目前为止,我收到了一些很棒的反馈,非常感谢你们提供的更多反馈。

                  我希望这会有所帮助! :)

                  【讨论】: