Logo
Section 1 / 11

FizzBuzz 问题

实现 FizzBuzz 问题,以熟悉 TDD 方法的基本流程。

导入

FizzBuzz 问题

实现 FizzBuzz 问题,以熟悉 TDD 方法的基本流程。

我们将开始使用 TDD 方法进行练习。在这一系列课程中,我们将通过该技术来实现一个编程练习(kata),所采用的示例 kata 是 FizzBuzz。

在开始之前,让我们先回顾一下它的规则:FizzBuzz 函数接收一个整数作为参数,并返回一个字符串。返回值根据以下条件决定:

  • 如果数字能被 3 整除,返回 Fizz。
  • 如果数字能被 5 整除,返回 Buzz。
  • 如果数字既能被 3 又能被 5 整除,返回 FizzBuzz。
  • 如果数字既不能被 3 也不能被 5 整除,返回该数字的字符串表示形式。

在这个 kata 中,我们可以明确地看出有四个需要实现的功能点(或需求)。通过使用 TDD 方法逐一实现这些功能,我们将熟悉这种开发方式,并为应对更复杂的项目做好准备。

基本场景

TDD 方法要求我们首先思考问题中最基础的部分。解决完这部分后,再逐步添加其他功能。每实现一个功能,都必须完整经历 TDD 的三个阶段:红(Red)、绿(Green)和重构(Refactor)。

红色阶段

让我们看看我们的初始状态是什么样的:

No configuration found for ID: 63fac1fd53f840439ff2fbfe9e7a9f9e56d51c08cc922b253e0cc1013892b677

值得注意的是,我们已经编写了第四个需求的最基本场景,即当传入的数字既不能被 3 也不能被 5 整除时的情况。让我们仔细分析这个解决方案。整个项目只包含两个文件:

  • fizzbuzz.go 文件将存放本次 kata 的核心逻辑。
  • fizzbuzz_test.go 文件将存放针对 FizzBuzz 函数的测试代码。

此外,在 TestFizzBuzz 函数中,我们遵循了 AAA(Arrange、Act、Assert)模式进行组织。当我们使用 go test -v -cover 命令运行测试时,出现了编译错误:./fizzbuzz_test.go:10:9: undefined: FizzBuzz。这是因为我们尚未在 fizzbuzz.go 文件中定义 FizzBuzz 函数。

注意:从本课起,我们始终使用命令 go test -v -cover。这样可以获取详细的输出信息,并查看实际的代码覆盖率。

TDD 强调在编写任何生产代码之前先写测试,因此出现编译失败是预期中的正常现象。

绿色阶段

我们仍处于 TDD 循环的红色阶段。此时,我们需要采取最小的一步操作,使程序从“红”进入“绿”。请看下面的代码片段:

No configuration found for ID: 987a7882ce8f26dce2e67c805787c9c645aedac0cc7fa3c88722b0e3b7e82865

我们在 fizzbuzz.go 文件中定义了 FizzBuzz 函数。这解决了控制台中的编译错误。我们引入了一个最基础的实现,即返回字符串类型的默认空值。虽然编译不再报错,但如果我们再次用相同的命令运行测试,会得到 fizzbuzz_test.go:14: expected "1" but got "" 的结果。这意味着尽管我们改进了实现,仍然处于“红”阶段。

现在,让我们看看如何真正走出“红”阶段:

No configuration found for ID: 94778925b58c43b073e3bb84712cef15310067f863fea01a26d853c7789748c5

注意:此时我们可能会想直接返回 input 变量的字符串格式。但这会违反 TDD 的原则。

只需简单地返回字符串 "1",我们就能成功退出“红”阶段,进入“绿”阶段。此时再次运行测试,结果为 PASS,且代码覆盖率达到 100%。

重构阶段

此阶段用于对测试代码和生产代码进行重构。请记住,在这个阶段允许对代码进行重构,因为此时已有测试保障了代码的正确性。每次重构后,都需要重新运行所有测试,以确保没有引入回归问题。如果无需重构,此阶段可以跳过。

让我们来看看如何对代码进行重构:

No configuration found for ID: 894269a46e64492d24b5adacf4828b64b8886ea723ef1ce296eb01645224bdb2

重构仅作用于 TestFizzBuzz 函数,特别是其中的“断言”部分:

  • 我们移除了断言中的魔法字符串 "1",改用 strconv.Itoa 函数将整数转换为字符串。
  • 引入了包 "github.com/stretchr/testify/assert",使断言更加简洁易读。

为了验证重构是否成功,我们再次运行测试,结果与之前一致:PASS,代码覆盖率仍为 100%。

Go 与测试

FizzBuzz:非整除要求