如何开始测试驱动开发

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

Internet Archive Book Images。由 Opensource.com 修改。CC BY-SA 4.0

我经常被那些赞同转向测试驱动开发 (TDD) 的软件开发人员所接近。他们理解,首先描述期望,然后编写代码来满足这些期望是编写软件的最佳方式。他们也同意,首先编写测试不会引入任何额外开销,因为反正他们都必须编写测试。尽管如此,他们仍然发现自己陷入困境,不清楚要测试什么、何时测试以及如何测试。本文将回答这些问题。

首先,一个类比

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

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

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

测试策略

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

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

还有另一种方法是使用电压表并连接正极 (+) 和负极 (-) 端子,看看电压表是否记录到 12.6 至 14.7 伏范围内的电压输出。如果记录到,您可以确认,是的,汽车电池功能如预期。

以上三个假设的例子说明了汽车电池的不同测试方法如何与三类测试策略对齐

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

TDD 完全是关于单元测试

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

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

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

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

模拟真实条件

在汽车电池的情况下,仅通过使用简单的电压表,您就可以模拟汽车电池的运行环境。您不必花费巨资来提供完整的体验(例如,功能齐全的汽车,从波特兰到西雅图的漫长而危险的旅程)才能确信您的汽车电池确实如预期般运行。

这就是单元测试简单性的魅力所在。它易于模拟,易于测量,易于让练习者确信一切都如预期般工作。

那么是什么使这种魔力成为可能呢?答案很简单——缺乏依赖性。汽车电池不依赖于与汽车相关的任何事物。它也不依赖于与从波特兰到西雅图的公路旅行相关的任何事物。请记住,随着您分解的系统组件变得越来越不依赖于其他组件,您的解决方案将变得越来越可靠。

结论

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

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

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 (未验证)

很棒的文章!谢谢你:)

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