如何开始测试驱动开发

了解在 TDD 系统中何时、什么以及如何进行测试。
107 位读者喜欢这篇文章。
How Linux got to be Linux: Test driving 1993-2003 distros

互联网档案馆图书图片。由 Opensource.com 修改。CC BY-SA 4.0

我经常遇到对转向测试驱动开发 (TDD) 感兴趣的软件开发人员。他们理解首先描述期望,然后编写代码来满足这些期望是编写软件的最佳方式。他们也同意首先编写测试不会引入任何开销,因为无论如何他们都必须编写测试。然而,他们发现自己陷入困境,不清楚要测试什么、何时测试以及如何测试。本文将回答这些问题。

首先,一个类比

想象一下,您正在一个团队中工作,该团队被要求制造一辆赛车。 目标是交付一种产品,使工作人员能够驾驶该车从一个城市(例如俄勒冈州的波特兰)到另一个城市(例如华盛顿州的西雅图)。

您的团队可以通过几种不同的方式来设计和制造这辆车。一种方法是手工制作一个独特的、单片的车辆,其中所有部件都是自制的并且紧密耦合的。另一种方法是只使用预制部件并将它们缝合在一起。并且这两种极端方法还有许多其他的排列组合。

假设您的团队选择手工制造赛车的组成部分。一辆车需要一个电池才能运行。 为了便于类比,请关注定制的车载电池。 您将如何测试它?

测试策略

测试定制车载电池的一种方法是聘请一个测试团队,将带有电池的汽车运送到波特兰,然后让测试团队驾驶该汽车从波特兰到西雅图。如果汽车到达西雅图,您可以确认,是的,车载电池按预期运行。

测试定制车载电池的另一种方法是将其安装在汽车中,看看发动机是否启动。如果发动机启动,您可以确认,是的,车载电池按预期运行。

还有一种方法是使用电压表并将正极 (+) 和负极 (-) 端子连接起来,以查看电压表是否记录到 12.6 至 14.7 伏范围内的电压输出。如果确实如此,您可以确认,是的,车载电池按预期运行。

以上三个假设的例子说明了测试车载电池的不同方式如何与三种类别的测试策略保持一致

  1. 雇用测试团队驾驶汽车从波特兰到西雅图符合**系统或端到端测试策略**。
  2. 将电池安装在汽车中并验证发动机是否启动符合**集成测试策略**。
  3. 测量车载电池的电压输出以验证其是否在预期范围内符合**单元测试策略**。

TDD 完全是关于单元测试的

我希望这些示例为区分单元、集成和系统端到端测试提供简单的指导原则。

请记住这些指导原则,在您的 TDD 实践中_永远不要_包含集成或系统测试,这一点非常重要。在 TDD 中,预期的结果始终是微观结果。测量车载电池的电压输出是微观结果的一个很好的例子。车载电池是一个功能单元,不能轻易地分解为几个更小的功能单元。 因此,它是编写单元测试(即,描述预期的可测量输出)的完美候选对象。

您还可以以以下形式编写对您的期望的描述:“我期望在转动钥匙的事件发生时汽车发动机启动。” 但是,该描述不符合单元测试的条件。 为什么? 因为汽车的粒度级别不够低。 在软件工程术语中,汽车不体现单一职责原则 (SRP)。

当然,您还可以以以下形式编写对您的期望的描述:“我期望从波特兰开始旅程的汽车在 x 小时后到达西雅图”,该描述不符合单元测试的条件。 从波特兰到西雅图的汽车旅程的许多方面都可以测量,因此这种端到端的描述绝不应成为 TDD 的一部分。

模拟真实条件

对于车载电池,只需使用一个简单的电压表,您就可以模拟车载电池的运行环境。 您不必花费提供完整的体验(例如,一辆功能齐全的汽车,一段从波特兰到西雅图的漫长而危险的旅程)的费用,就可以确信您的车载电池确实按预期运行。

这就是单元测试的简洁之美。 它易于模拟、易于测量,并且易于离开练习,并确信一切都按预期工作。

那么是什么促成了这种魔力? 答案很简单——_缺少依赖项_。 车载电池不依赖于与汽车相关的任何东西。 也不依赖于与从波特兰到西雅图的公路旅行相关的任何东西。 请记住,随着您分解的系统组件对其他组件的依赖性越来越小,您的解决方案就会变得越来越可靠。

结论

软件工程的艺术在于能够将复杂的系统分解为小的组成元素。 每个单独的元素都必须缩小到尽可能小的表面积。 一旦您在分解系统的过程中达到该点,您就可以很容易地将注意力集中在描述您对每个单元输出的期望上。 您可以通过遵循一种形式化的模式来做到这一点,在该模式中,您首先描述_前提条件_(即,假设存在这样的值),_操作_(即,假设发生这样的_事件_),以及_结果_或_后置条件_(即,您希望可以测量这样的值)。

接下来要读什么
标签
User profile image.
自 1990 年以来,Alex 一直在从事软件开发。他目前的热情是如何将软性元素带回软件中。他坚信,我们的行业已经达到了这样的复杂程度,可以完全实现这个崇高的目标(即将软性元素带回软件中)。

5 条评论

你好 Alex,

感谢您分享这篇精彩的文章,

测试驱动开发是软件行业中最好和最有趣的部分之一。 我在阅读您的文章时学到了很多东西,请继续分享您宝贵的知识。 您也可以查看我的文章,它可能对您有所帮助: https://www.testrigtechnologies.com/test-automationtop-10-things-to-kno…

值得注意的是,Smalltalk 在发明(或重新发现)TDD 方面发挥了重要作用,这要归功于 Kent Beck。

在这种情况下,对较低级别部件的要求似乎是众所周知的,就好像它们是业务要求的一部分。 在大多数情况下,业务要求更像是“制造一辆汽车”。 因此,有很多不同的方法可以做到这一点。 假设您决定制造一台汽油发动机,那么您继续使用 TDD 来开发您的汽油发动机。 一个月后,您意识到您在汽油上花费了太多钱,而电动发动机实际上效率更高。 因此,您花费了大量时间为猜测的要求编写测试,结果证明是错误的。 现在您必须删除这些测试并进行重构。

这是 TDD 的常态吗,您必须猜测较低级别的抽象,然后为它们编写测试? 或者 TDD 是否也以某种方式帮助您正确地获得这些较低级别的位,而本文只是没有演示这一点。

不,在 TDD 中,我们不进行猜测。 我们遵循极限编程 (XP) 实践的三 C 方法论。 这三个 C 是
1. 卡片
2. 对话
3. 确认示例
它始于业务制定一个假设。 例如,产品负责人想要发展他们的产品,他们集思广益并得出一个(或两个)假设。 然后,他们将该假设写在一张方便的卡片上。
然后,该卡片与团队共享,并引发进一步的对话。 您这是什么意思,您那是什么意思,您能否澄清这一部分,我可以提出这个想法吗,等等。 在对话耗尽后,它应该产生一个或多个确认示例。 这些确认示例必须包含具体值。
TDD 基于这些具体值。 没有什么留给猜测。
如果业务/利益相关者无法获得具有具体值的确认示例,那么开始实施业务假设没有任何意义。 因为,如果您缺少规范,您将实施什么?
仅仅提供一份愿望清单(类似于“我希望制造一种畅销且让我致富的产品!”)是行不通的。 在开始构建软件之前,必须提供更多具体细节,甚至是令人痛苦的细节。

回复 作者:Avi Block (未验证)

很棒的文章! 谢谢你:)

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.