代码之家  ›  专栏  ›  技术社区  ›  Breton

测试驱动开发:如果bug在接口中呢?

  •  8
  • Breton  · 技术社区  · 15 年前

    coding horror post ,其中一条评论触动了我的神经:

    这是测试驱动的设计/重构应该修复的情况。如果(big If)您对接口进行了测试,那么重写实现是没有风险的,因为您将知道是否捕获了所有内容。

    现在在理论上我喜欢测试驱动开发的想法,但是我一直在努力让它起作用,它并没有特别好,我摆脱了这个习惯,接下来我知道我最初编写的所有测试不仅没有通过,而且不再是系统设计的反映。

    我以前试过问这个问题,无论是同龄人还是网上,但我从来没有听到过一个非常满意的答案。... 哦等等。。问题是什么?

    如何将测试驱动的开发与必须更改以反映对问题空间日益增长的理解的设计相结合?你如何使TDD实践为你而不是对你起作用?

    更新: 我仍然不认为我完全理解这一切,所以我不能真正决定接受哪个答案。我在理解上的飞跃大多发生在评论部分,而不是答案部分。以下是我迄今为止最喜欢的收藏:

    在软件开发方面确实是满员 该死的。但不要注销TDD 因为它的一些支持者 极易被炒作。我找到了 帮助我理清思路 复制错误并修复它们,然后 当它们开始变得丑陋的时候”

    -克里斯托弗·约翰逊

    只是界面的一部分 已经改变了,考虑一下 你很幸运能考得好 其他对象依赖于它。”

    -R编码器

    “在TDD中,编写测试的原因 自动化测试是为了 将它们作为设计和代码重用 进化。当测试中断时,它意味着 设计决策。也许那是 很高兴能尽快得到反馈 有可能。”

    -克里斯托弗·约翰逊

    [关于测试接口]“测试会插入一些元素, 插入的元素数,检查 contains()为它们返回true 但不是为了那些 插入,检查remove()是否有效, 所有实现都相同,并且 对于每个实现而不是拷贝 它。所以当界面改变时, 一次编码,不是每次编码一次 执行。”

    迈克尔·博格沃德

    9 回复  |  直到 15 年前
        1
  •  3
  •   Diego Dias    15 年前

    TDD的一个实践是使用婴儿步骤(在乞讨中可能非常无聊),这是使用非常小的步骤,以便您了解您的问题空间,并为您的问题提供一个良好和满意的解决方案。

    所以我建议你把注意力集中在婴儿的步骤上,以便得到一个合适的可测试的设计

        2
  •  1
  •   Kristopher Johnson    15 年前

    我不认为任何真正的TDD实践者会声称它完全消除了错误或回归的可能性。

    记住,TDD基本上是关于 设计 ,不是关于 或者质量控制。说“我所有的测试都通过”并不意味着“我完成了”

    如果您的需求或高级设计发生了重大变化,那么您可能需要扔掉所有测试和所有代码。有时候事情就是这样。这并不意味着TDD帮不了你。

        3
  •  1
  •   rcoder    15 年前

    如果应用得当,TDD实际上会让你的生活在不断变化的需求面前变得更加轻松。

    另一方面,如果您只是在设计代码之后对其进行单元测试,那么当需求发生变化时,您很可能会遇到问题。当子系统改变时,测试会很快失败(因为它们有效地标记了回归)和那些脆弱的测试是有区别的,因为它们依赖于太多不相关的系统状态。前者应该可以通过几行代码来修复,而后者可能会让你绞尽脑汁数小时试图解开它们。

        4
  •  1
  •   soru    15 年前

    唯一正确的答案是 这取决于 .

    • 它不适合你的 环境与饮食
    • 有办法做正确的TDD,这样 它既降低成本又增加成本 质量。
    • 有办法 可能被称为TDD,也可能不被称为TDD 可能更适合,也可能不适合 你的特殊情况。

    事实上,“软件”和“硬件”都是千差万别的,没人会想到买一本关于桥梁制作的书来设计一个电子设备或建造一个花园小屋。

        5
  •  1
  •   Community paulsm4    7 年前

    我想你对TDD有些误解。为了更好地解释和举例说明它是什么以及如何使用它,我建议阅读肯特贝克的 Test-Driven Development: By Example .

    以下是一些进一步的评论,可能有助于您理解TDD是什么以及为什么有些人会信誓旦旦地说:

    • TDD公司 做设计。

    “你如何使TDD实践对你而不是对你起作用?”

    • 很多TDD教程都提供了对每个类的每个方法的非常详细的测试。在现实生活中,人们不会这样做。为每个setter、每个getter等编写测试是愚蠢的。Beck的书很好地展示了如何使用TDD快速设计和实现一些东西,只有当事情变得棘手时才会放慢到“婴儿步骤”。见 How Deep Are Your Unit Tests 关于这一点的更多信息。

    • 当您做出的更改导致测试中断时,这并不是一件坏事,而是有价值的反馈。设计确实会改变,你的测试也不是一成不变的。如果你的设计变化太大,以至于一些测试不再有效,那么就扔掉它们吧。写下你需要对新设计充满信心的新测试。

        6
  •  0
  •   Michael Borgwardt    15 年前

    潜水和固定“臭虫”,但 测验。

    TDD的一个基本原则是避免生产代码和测试代码中的重复。如果一个单一的设计变更意味着你必须重写所有的东西,那么你没有做TDD(或者根本没有正确地做TDD)。

    一些 生产代码和一些测试,但不是所有的测试,而且更改大多很简单,甚至可以通过重构工具自动完成。

        7
  •  0
  •   neoneye    15 年前

    在不知道什么在UI中最有效的情况下编写代码,同时编写单元测试。那很费时。最好开始制作一些图形用户界面的原型,以便正确地进行交互。。然后用单元测试重写(如果雇主允许)。

        8
  •  0
  •   TrueWill    15 年前

    持续集成是一个关键。如果您的测试在每次签入源代码管理时都自动运行(如果失败,其他人都会看到),则更容易避免“过时”的测试并保持绿色。

    另见 http://thought-tracker.blogspot.com/2005/11/notes-on-pragmatic-unit-testing.html -一定要买这本书!

    编辑:也许我看错了。假设您有一个要重新设计的遗留代码库。我要做的第一件事是为当前行为添加测试。没有测试的重构是有风险的——你可能会改变行为。在那之后,我将开始清理设计,在每个步骤之后运行我的单元测试。这会让我相信我的改变没有破坏任何东西。

    在某个时候API可能会改变。这将是一个突破性的变化-客户端将必须更新。测试会告诉我这很好,因为我必须更新任何现有的客户端(包括测试)。

    现在不是TDD了。但想法是一样的——测试是行为规范(是的,我在BDD中添加了阴影),它们让我有信心重构实现,同时确保我保留行为(以及在更改接口时让我知道)。

    在实践中,我发现TDD能给我关于糟糕的界面设计的即时反馈。我是我的第一个客户-我知道什么时候我的API很难使用。

        9
  •  0
  •   ndp    15 年前

    我们倾向于做很多事 预先设计TDD,知道它可以改变。我已经通过巨大的旋转(这是一个web应用程序,不,这是一个RESTful服务器,不,这是一个bot)。这些测试为我提供了重构、重构和演化代码的能力,比未经测试的代码要容易得多。虽然看起来很矛盾,但这是真的——即使你有更多的代码,你也能够做出重大的改变 在现有功能中没有任何东西被破坏。

    我理解你的担心,基本假设的改变会让你放弃测试。这似乎很直观,但我个人还没有看到。有些测试是可行的,但大多数仍然有效——通常一个重大的改变并不像最初看起来那么重要。另外,随着你越来越擅长编写测试,你倾向于编写不那么脆弱的测试,这对你有帮助。