遵循 RGR 循环
我们在上一章中看到,单个单元测试被分成三个部分,分别称为 Arrange
、Act
和 Assert
部分。这形成了一个简单的工作节奏,指导我们编写每个测试。它迫使我们设计代码的使用方式——即代码的外部。如果我们把一个对象看作是一个封装边界,那么讨论什么在边界内,什么在边界外就很有意义。公共方法形成了我们对象的外部。Arrange
、Act
和 Assert
的节奏帮助我们设计这些。
我们在这里使用 “节奏” 一词时,几乎是从音乐的角度来理解的。它是一个不断重复的主题,将我们的工作串联在一起。编写测试、编写代码、改进代码,再决定下一步写哪个测试,形成了一个规律的工作流程。每个测试和代码片段都是不同的,但工作节奏是相同的,就像是一首不断变化的歌中的稳定节拍。
一旦我们编写完测试,我们就开始创建对象内部的代码——私有字段和方法。为此,我们使用另一个节奏,叫做 RGR。这是一个三步过程,帮助我们建立对测试的信心,创建代码的基本实现,然后安全地进行优化。在本节中,我们将了解每个阶段需要做的工作。
从 Red 开始

我们总是从第一阶段开始,称为红色阶段。这个阶段的目标是使用 Arrange
、Act
和 Assert
模板,让我们的测试运行起来,并准备好测试我们接下来编写的代码。这个阶段最重要的部分是确保测试不通过。我们称之为失败的测试,或者红色测试,因为大多数图形化的测试工具用红色来表示失败的测试。
这有点违反直觉,不是吗?我们通常在开发中目标是第一次就把事情做对。然而,在这个阶段我们希望测试失败,以便让我们确信它正常工作。如果测试此时通过,那就有问题了。为什么它会通过?我们知道我们还没有编写任何我们正在测试的代码。如果此时测试通过,那意味着我们要么根本不需要编写新代码,要么我们在测试中犯了错误。进一步阅读部分提供了一个链接,列出了测试可能无法正确运行的八个原因。
这里最常见的错误是断言错误。在继续之前,先找出并修复这个错误。我们必须确保红色测试在这里存在,这样我们才能看到它从失败到通过的变化,随着我们正确添加代码。
保持简单 - 转到 Green

一旦我们有了失败的测试,就可以自由编写使其通过的代码。我们称这为生产代码——它将成为我们生产系统的一部分。我们将生产代码视为黑盒组件。可以将其想象为电子产品中的集成电路,或者某种机械密封单元。该组件有内部和外部。内部是我们编写生产代码的地方,它隐藏了实现的 数据和算法。我们可以使用任何我们选择的方法——面向对象、函数式、声明式或过程式,随我们喜欢。外部是 应用程序接口(API)。这是我们用来连接和使用组件以构建更大软件部分的部分。如果我们选择面向对象的方法,这个 API 将由对象的公共方法组成。使用 TDD 时,第一个连接的部分是我们的测试,这可以让我们快速反馈连接的易用性。
以下图表展示了不同的部分——内部、外部、测试代码以及我们组件的其他使用者:

因为我们的实现是封装的,所以我们可以在以后根据更多的学习来改变它,而不会破坏测试。
这个阶段有两个指导原则:
-
使用最简单的代码:使用最简单的代码非常重要。我们可能会有诱惑去使用过度工程化的算法,或者只是为了使用最新的语言特性而使用它。要抵制这种诱惑。在这个阶段,我们的目标是让测试通过,仅此而已。
-
不要过度思考实现细节:我们不需要过度思考这一点。我们不需要在第一次尝试时写出完美的代码。我们可以写一行代码、一个方法、几个方法,或者完全新的类。我们将在下一步改进这段代码。只需记住让测试通过,不要超出该测试所涵盖的功能范围。
重构为清洁代码

这是我们进入软件工程模式的阶段。我们已经有了一些工作正常、简单的代码,并且测试通过了。现在是时候将它提炼成干净的代码——意味着将代码写得更易于阅读。凭借测试通过所带来的信心,我们可以自由地应用任何有效的重构技术。我们可以在这个阶段使用的一些重构技术包括:
-
提取方法以去除重复代码
-
重命名方法,以更好地表达它的功能
-
重命名变量,以更好地表达它包含的内容
-
将一个长方法拆分成几个较小的方法
-
提取一个较小的类
-
将长参数列表合并为一个类
所有这些技术的目标是:让我们的代码更容易理解。这样做将使其更易于维护。记得在这些更改过程中保持绿色测试通过。到这个阶段结束时,我们将拥有一个覆盖生产代码的单元测试,而我们已经将代码工程化,使其在未来更易于使用。这是一个很好的状态。
现在,我们已经熟悉了 RGR 周期中每个阶段该做什么,让我们将其应用到我们的 Wordz 应用程序中。