开始TDD - 挑战?解决方案?建议?

时间:2008-08-24 10:43:18

标签: unit-testing language-agnostic tdd

好的,我知道已经有关于getting started with TDD的问题。但是,我想我知道一般的共识是就这样做但是,我似乎有让我的头脑进入游戏有以下问题:

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

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

11 个答案:

答案 0 :(得分:50)

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

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

考虑到上述段落,让我们看一下你的问题:

  1. 如果我在我的系统中使用集合,那么我将设置一个期望,以确保调用代码插入项目然后断言集合的计数。我不一定在我的内部列表上测试Add方法。我只是确保在调用添加项的方法时调用它。我通过在我的测试框架中添加一个模拟框架来实现这一点。
  2. 测试字符串作为输出可能很乏味。你无法解释每一个结果。您只能根据被测系统的功能测试您的期望。您应该始终将测试分解为它正在测试的最小元素。这意味着你将进行大量的测试,但是测试虽然小而快,只测试它们应该做什么,没有别的。
  3. 有很多开源测试框架可供选择。我不打算争辩哪个是最好的。找到你喜欢的并开始使用它。
  4. 您所能做的就是设置测试以说明您想要发生的事情。如果出现导致您的功能出现错误的情况,至少您需要测试该方案添加到测试中的功能,然后更改您的功能直到测试通过。找到我们可能错过测试的方法之一是使用code coverage
  5. 我向你介绍了问题一的答案中的嘲弄术语。当你为你的TDD武器库引入模拟时,它会极大地使测试更容易抽象出不属于被测系统的部分。以下是有关模拟框架的一些资源:

    除了阅读有关流程之外,帮助使用TDD的一种方法是观察人们这样做。我建议在DNRTV观看JP Boodhoo的屏幕演员。看看这些:

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

    我认为如果我没有通过在Test Driven Development on Pragmatic Programmer添加Kent Beck的新系列来更新这一点,我会对社区造成不公正。

答案 1 :(得分:6)

根据我自己的经验:

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

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

  3. NUnit是要走的路。

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

答案 2 :(得分:2)

我对此的看法如下:

  • +1用于不测试框架代码,但您可能仍需要测试从框架类派生的类。
  • 如果某些类/方法很难测试,那么很可能表明设计出了问题。我尝试遵循“1类-1责任,1方法 - 1动作”原则。这样,您可以通过较小的部分更轻松地测试复杂的方法。
  • +1 for xUnit。对于Java,您也可以考虑使用TestNG
  • TDD不是单一事件,而是一个过程。因此,不要试图从一开始就设想一切,但要确保一旦发现,代码中发现的每个错误都会被测试覆盖。

答案 3 :(得分:2)

我认为最重要的事情(实际上是以某种递归的方式取得的巨大成果之一)TDD是对依赖关系的成功管理。您必须确保模块经过单独测试,无需进行复杂的设置。例如,如果您正在测试最终发送电子邮件的组件,请使电子邮件发件人成为依赖关系,以便您可以在测试中模拟它。 这导致第二点 - 嘲笑是你的朋友。熟悉模拟框架和他们推广的测试风格(行为,而不是基于经典状态),以及他们鼓励的设计选择("Tell, don't ask"原则)。

答案 4 :(得分:2)

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

无论如何,回答你的问题

  1. 除非你写了,否则你不必测试你“知道”会起作用的东西。你没有写泛型,微软做了;)
  2. 如果您需要为测试做很多事情,也许您的对象/方法也做得太多了。
  3. 下载TestDriven.NET以立即开始在Visual Studio上进行单元测试(除非是Express版本)
  4. 只测试正确的事情。您不需要 来测试可能出错的所有内容:您必须等待测试失败。
  5. 说真的,就这么做,老兄。 :)

答案 5 :(得分:0)

无论如何,我不是TDD的专家,但这是我的看法:

  • 如果它完全无关紧要(getter / setters等),请不要测试它,除非你因为某种原因对代码没有信心。
  • 如果它是一个非常简单但非平凡的方法,请测试它。无论如何,测试可能很容易写。
  • 当谈到预期不会发生什么时,我会说如果某个潜在问题是您正在测试的类的责任,则需要测试它是否正确处理它。如果不是当前班级的责任,请不要对其进行测试。

xUnit测试框架通常是免费使用的,所以如果你是.Net人,请查看NUnit,如果你的Java是你的东西,请查看JUnit。

答案 6 :(得分:0)

上述建议很好,如果你想要一个免费框架列表,你必须看起来不比维基百科上的xUnit Frameworks List更远。希望这会有所帮助:)

答案 7 :(得分:0)

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

1-如果你没有写它,不要测试它。如果你写了它而你没有测试它就不存在了。

3-正如大家所说的那样,xUnit的自由和伟大。

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

答案 8 :(得分:0)

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

我一直认为“为了证明这适用于所有情况,我需要编写的最少代码量是多少?”

答案 9 :(得分:0)

在过去的一年里,我越来越相信TDD的好处。 我沿途学到的东西: 1)依赖注入是你的朋友。我不是在讨论控制容器和框架的反转来组装插件体系结构,只是将依赖项传递给被测试对象的构造函数。这为您的代码的可测试性带来了巨大的回报。 2)我带着皈依者的激情/热情开始,抓住了一个嘲弄的框架,开始尽我所能地使用模拟。这导致了脆弱的测试,需要大量的痛苦设置,并且一旦我开始任何重构就会崩溃。使用正确类型的测试双。假装你需要尊重界面,存根以将数据反馈给被测对象,只在你关心交互的地方进行模拟。 3)测试应该很小。目标是在每个测试中测试一个断言或交互。我试着这样做,大多数时候我都在那里。这是关于测试代码的稳健性,以及当您稍后需要重新访问时测试的复杂程度。

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

答案 10 :(得分:0)

正如对此的补充,我想我会说blog post对我开始测试的想法(在此讨论和我自己的研究之后)提出了TDD – Getting Started with Test-Driven Development,因为它可能对人们有用查看此主题。

“{{3}}” - 到目前为止我收到了一些很好的反馈意见,我们真的很感激你们所提供的。

我希望这有帮助! :)