【问题标题】:TDD: Where to start the first test [closed]TDD:从哪里开始第一个测试[关闭]
【发布时间】:2009-06-01 15:37:50
【问题描述】:

所以我做了一些单元测试,并且有编写测试的经验,但我还没有完全接受 TDD 作为一种设计工具。

我目前的项目是改造现有系统,该系统会生成序列号,作为公司组装过程的一部分。由于查看了现有系统,我对当前的流程和工作流程有所了解。我还列出了新要求以及它们将如何修改工作流程。

我觉得我已经准备好开始编写程序了,我决定强迫自己最终从头到尾做 TDD。

但现在我不知道从哪里开始。 (我也想知道我是否已经对用户的程序流程有所了解,从而欺骗了 TDD 流程。)

用户流程实际上是连续的,只是一系列步骤。例如,第一步是:

  • 用户提交制造订单号并收到该订单物料清单的可序列化部件号列表

当用户选择其中一个零件号时开始下一步。

所以我想我可以将这第一步作为起点。我知道我想要一段代码,它接受制造订单号并返回零件号列表。

// This isn't what I'd want my code to end up looking like
// but it is the simplest statement of what I want
IList<string> partNumbers = GetPartNumbersForMfgOrder(string mfgOrder);

阅读 Kent Becks 的示例书,他谈到选择小型测试。这似乎是一个相当大的黑匣子。它需要一个制造订单存储库,我必须爬取产品结构树才能找到此制造订单的所有适用部件号,我什至根本没有在代码中定义我的域模型。

因此,一方面这似乎是一个糟糕的开始 - 一个非常通用的高级功能。另一方面,我觉得如果我从较低级别开始,我真的只是在猜测我可能需要什么,这似乎是反 TDD。


附带说明...这是您使用故事的方式吗?

作为汇编程序 我想获得制造订单上的零件编号列表 这样我就可以选择序列化哪一个了

说实话,汇编程序永远不会这么说。一个组装者想要的只是完成制造订单的操作:

作为汇编程序 我想用序列号标记零件 这样我就可以完成制造订单上的操作了

【问题讨论】:

    标签: tdd agile


    【解决方案1】:

    我会这样开始。假设您完全没有此应用程序的代码。

    1. 定义用户故事及其带来的业务价值:“作为用户,我想提交制造订单号和该订单的零件号列表,以便我可以将列表发送到库存系统”李>
    2. 从用户界面开始。创建一个非常简单的页面(假设它是一个 Web 应用程序),其中包含三个字段:标签、列表和按钮。这已经足够了,不是吗?用户可以复制列表并发送到 inv 系统。
    3. 使用模式作为设计的基础,例如 MVC。
    4. 为从 UI 调用的控制器方法定义一个测试。您在这里测试控制器是否正常工作,而不是数据是否正确:Assert.AreSame(3, controller.RetrieveParts(mfgOrder).Count)
    5. 编写控制器的简单实现以确保返回某些内容:return new List&lt;MfgOrder&gt;{new MfgOrder(), new MfgOrder(), new MfgOrder()}; 例如,您还需要实现 MfgOrder 的类。
    6. 现在您的 UI 可以正常工作了!工作不正确,但工作。因此,让我们期望控制器从服务或 DAO 获取数据。在测试用例中创建一个 Mock DAO 对象,并添加调用“partsDao.GetPartsInMfgOrder()”方法的期望。
    7. 使用该方法创建 DAO 类。从控制器调用方法。您的控制器现已完成。
    8. 创建一个单独的测试来测试 DAO,最后确保它从 DB 返回正确的数据。
    9. 继续迭代,直到全部完成。过一会儿,你就会习惯了。

    这里的要点是将应用程序分成非常小的部分,并单独测试这些小部分。

    【讨论】:

      【解决方案2】:

      这完全可以作为开始测试。有了这个,你定义了预期的行为——它应该如何工作。现在,如果您觉得自己比您想要的要大得多。.您可以暂时忽略此测试并编写一个更细粒度的测试,该测试将部分或至少在中途取出。然后是其他测试,这些测试将带您朝着通过第一个大测试的目标前进。每一步都进行红绿重构。

      小型测试,我认为你不应该在一次测试中测试很多东西。例如在我使用 D 上的这些参数调用 Method1()、Method2() 和 Method3() 之后,组件 D.A、B 和 C 是否在 state1、state2 和 state3 中。 每个测试应该只测试一件事。您可以搜索 SO 以获得良好测试的质量。但我认为您的测试是一个小型测试,因为它简短且专注于一项任务 - “从制造订单中获取零件编号”

      更新:作为一个 To-Try 建议(来自 Beck 的书中的 AFAIR),您可能想坐下来在一张纸上列出 SUT 的单行测试列表。现在您可以选择最简单的(您有信心能够完成的测试。)以建立一些信心。或者您可以尝试一个您有 80% 的信心但有一些灰色区域(我的选择也是如此)的,因为它会帮助您一路了解 SUT。保留那些你不知道如何进行的最后......希望在更容易完成的时候它会更清楚。当它们变成绿色时,将它们一一清除。

      【讨论】:

      • 所以这让我放心,我坐下来写测试。甚至考虑如何编写它也是一种设计经验。我不确定我是否对我的测试感到满意,但这是一个起点,让我思考了一些事情。
      • 这正是 TDD 最重要的贡献。它从客户的角度推动您的设计 - 迫使您只添加至少一个客户所需的功能。最初,您可能会选择伪造合作者,但这仍然可以帮助您确定他们之间最简单的接口——这是一个巨大的胜利。在未来的功能中没有很好的或可能需要的功能;此外,持续重构有助于使您的设计保持简单、易于理解并因此可维护。
      • 我回去阅读了贝克的书的前 40-50 页,自上次阅读(几个月前)以来,有些东西沉没了。有帮助的两件事是:a)您可以通过犯罪来通过测试;b)您在绿色后立即重构。是的,对 SUT 的关注和思考对我很有帮助,尤其是考虑到 SUT 可能存在的所有环境——它会导致更强大、更不易碎的测试。
      【解决方案3】:

      我认为你有一个良好的开端,但并不完全这么看。应该产生更多测试的测试对我来说完全有意义,就好像您考虑一下一样,您知道制造订单号或零件号是什么吗?您必须构建可能导致其他测试的那些,但最终您会开始进行我相信的小测试。

      这是一个可能需要稍微分解的故事:

      • 作为用户,我想提交制造订单号并接收该订单物料清单的可序列化部件号列表

      我认为关键是将事物一遍又一遍地分解成小块,从而构建整个事物。这种“分而治之”的技术有时很方便。 ;)

      【讨论】:

      • 你忘记了故事的第三部分,好处。您那里还有实施细节,这些细节不会带来任何商业利益(可序列化)。我想说一个更好的故事是“作为用户,我想提交一个制造订单号和该订单的零件号列表,以便我可以将列表发送到库存系统”。
      • Serializable 在那种情况下不是实现,它是一个领域术语,表示哪些部分可以带有序列号,所以它很重要(据我了解要求)。
      • 如果是这样,那你是对的。领域专业知识就是一切。
      • 是的,对不起,它有丹尼斯提到的内涵。
      【解决方案4】:

      好吧,当我第一次尝试 TDD 时,你遇到了完全相同的墙 :)

      从那以后,我放弃了它,只是因为它使重构过于昂贵——而且我倾向于在开发的初始阶段进行很多重构。

      抛开那些脾气暴躁的话,我发现 TDD 最受监督和最重要的方面之一是它迫使您在实际实现类接口之前定义它们。当您需要将所有零件组装成一个大产品(嗯,组装成子产品;))时,这是一件非常好的事情。在编写第一个测试之前,你需要做的是在编码之前准备好你的域模型、部署模型,最好是一大块类图——仅仅因为你需要识别你的不变量、最小值和最大值等.,在您可以测试它们之前。您应该能够在设计中的单元测试级别上识别这些。

      Soo,根据我的经验(不是一些喜欢将现实世界类比映射到 OO 的作者的经验),TDD 应该是这样的:

      1. 根据需求规范创建部署图(ofc,没有什么是一成不变的)
      2. 选择要实施的用户故事
      3. 创建或修改您的域模型以包含此故事
      4. 创建或修改您的类图以包含这个故事(包括各种设计类)
      5. 识别测试向量。
      6. 根据您在第 4 步中创建的界面创建测试
      7. 测试测试(!)。这是非常重要的一步..
      8. 实现类
      9. 测试类
      10. 去和你的同事喝杯啤酒吧 :)

      【讨论】:

      • 如果你这样做,你就不是在做测试驱动开发。您正在编写测试,但不是从测试用例中推导出设计。
      • 是的,好吧,这是旁观者的看法 :) 在我看来,你不能 100% 地从测试原因中推导出你的设计。至少不是有效的-恕我直言。测试是针对实现细节的,而不是针对设计的。再说一次,我个人的观点。
      猜你喜欢
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      相关资源
      最近更新 更多