从内部开始测试

在这一部分,我们将回顾我们在 TDD 活动中选择的起点。首先要看的是软件系统的内部,从细节开始。

在开始构建软件时,我们显然需要从某个地方开始。一个起点是一些细节。软件由相互连接的小组件组成,每个组件执行整个任务的一部分。一些组件来自库代码。许多组件是定制的,以提供我们应用程序所需的功能。

那么,开始构建的一个地方就是在这个软件系统的内部。从一个整体的用户故事开始,我们可以想象一个可能对我们有用的小组件。我们可以围绕这个组件开始我们的TDD工作,看看它会引导我们到哪里。这是一种自底向上的设计方法,从较小的部分组合成整体。

如果我们考虑 Wordz 应用程序结构的简化版本,我们可以如下说明自内而外的方法:

image 2025 01 12 18 38 51 557
Figure 1. Figure 12.6 – Inside-out development

图中显示了 Score 组件被突出显示,因为这是我们使用自内而外方法开始开发的地方。其他软件组件被灰显。我们还没有设计这些部分。我们将从 Score 组件的一些行为的测试开始。我们将从那个起点向外扩展。

这种自内而外的 TDD 风格也被称为经典 TDD 或芝加哥 TDD。这是 Kent Beck 在他的书《测试驱动开发示例》中最初描述的方法。基本思想是从任何地方开始,为我们的代码创建任何有用的构建块。然后我们开发一个逐渐增大的单元,该单元包含早期的构建块。

自内而外的方法有一些优势:

  • 快速开始开发:在这种方法中,我们首先测试纯 Java 代码,使用熟悉的 JUnit 和 AssertJ 工具。不需要设置用户界面、Web 服务存根或数据库。不需要设置用户界面测试工具。我们直接使用 Java 编码。

  • 适用于已知设计:随着经验的积累,我们认识到一些问题有已知的解决方案。也许我们以前写过类似的东西。也许我们知道一些有用的设计模式。在这些情况下,从代码的内部结构开始是有意义的。

  • 与六边形架构配合良好:自内而外的 TDD 从内部六边形开始,即我们应用程序的领域模型。适配器层形成了一个自然的边界。自内而外的设计非常适合这种设计方法。

当然,没有什么是完美的,自内而外的 TDD 也不例外。一些挑战包括:

  • 可能浪费:我们以自内而外的 TDD 开始,猜测一些可能需要的组件。有时,后来发现我们不需要这些组件,或者我们应该将功能重构到其他地方。我们的初始努力在某种意义上是浪费的——尽管它帮助我们达到了这一点。

  • 实现锁定的风险:与前一点相关,有时我们从初始设计中前进,了解到更多关于我们正在解决的问题,但我们并不总是认识到沉没成本。总是有一种诱惑,继续使用我们之前编写的组件,即使它不再适合,只是因为我们投入了时间和金钱来创建它。

自内而外的 TDD 是一种有用的方法,最初由 Kent Beck 的书推广。然而,如果我们能从内而外开始,那么反过来呢?如果我们从系统的外部开始,向内工作呢?下一部分将回顾这种替代方法。