测试最佳实践

这结束了本章,也结束了我们对 Go 与 TDD 的探索。我们经历了一段奇妙的旅程,研究了许多库和技术,并将它们应用于我们的 BookSwap 应用程序以及较小的示例中。在这最后一节中,我们将回顾所学的经验教训,并制定一些测试最佳实践。

实现全面的测试策略需要持续的努力和组织内的文化转变,以拥抱质量并优先考虑测试。图11.4 总结了我们探讨的一些最佳实践,分为三个不同的类别:

image 2025 01 04 21 26 37 268
Figure 1. Figure 11.4 – Development, testing, and culture best practices

我们在本书中讨论了 14 个最佳实践,这些实践分为 3 个类别——开发、测试和文化。

开发最佳实践

以下是一些开发最佳实践(如图11.4 所示):

  1. 使用 TDD 在开发过程中编写测试:确保我们编写的代码经过测试的最佳方法是将其包含在开发过程中。代码永远不会未经测试就交付,开发人员会编写可测试、设计良好的代码。

  2. 使用接口包装依赖项:我们的代码通常依赖于其他组件。将我们包外部的依赖项用接口包装是一个好习惯,这样它们可以轻松替换,无论是通过测试代码还是另一个依赖项。我们在第3章《模拟和断言框架》中探讨了依赖项和接口。

  3. 重构代码以解决技术债务:代码应随着新功能的开发进行重构,以确保其保持高性能、可读性和易于维护。我们在第 7 章《Go 中的重构》中探讨了一些重构技术。测试将确保重构过程不会破坏任何功能。

  4. 编写能够处理各种输入的健壮代码:我们在第 10 章《测试边缘情况》中讨论了代码健壮性。它应该能够处理各种输入并返回格式良好的错误。

  5. 采用泛型以简化代码重用:正如我们在本章中看到的,泛型使我们能够编写能够处理不同数据输入的代码。这使我们能够使用适用于各种类型参数的可重用代码。

测试最佳实践

以下是一些测试最佳实践(如图 11.4 所示):

  1. 编写简单、隔离的测试:测试应该简单且与其依赖项隔离。这使我们能够避免设置大量服务,这可能会很麻烦并且可能会发生变化。相反,我们应该编写使用模拟来隔离测试 UUT 的集中测试。我们在第3章《模拟和断言框架》中探讨了模拟和依赖项。

  2. 使用表驱动测试来涵盖各种场景:编写表驱动测试的流行技术是轻松创建测试用例列表并运行它们。测试用例应在自己的子测试中运行,以创建结构良好的测试输出。我们在第4章《构建高效的测试套件》以及本章中探讨了这种技术。

  3. 在应用程序的每个级别编写测试:单元测试很快,但它们仅断言给定包的功能是正确的,而不是它能够与其他单元正确运行。正如第 1 章《掌握测试驱动开发》中介绍的测试金字塔所描绘的那样,我们应该编写自动化测试,以断言应用程序的各个单元能够正确集成和运行。

  4. 使用 Go 的测试包:虽然它最初可能看起来过于简单,但 testing 包提供了各种功能,使我们能够编写功能和非功能测试。我们在本书中探讨了这个包的功能。

  5. 使用第三方测试库:我们探讨了多个第三方测试库(testifyginkgogodog),它们补充了标准测试包,使我们更容易编写测试断言和创建模拟。

文化最佳实践

以下是一些文化最佳实践(如图11.4 所示):

  1. 记录客户需求:用户旅程和客户需求应成为我们编写的所有测试的核心。由于几乎不可能编写涵盖每个代码路径和交互的测试,工程师应确保对客户重要的事情得到优先考虑并由测试覆盖。

  2. 减轻错误和意外中断的影响:在微服务架构中,几乎不可能确保零中断。我们应该对我们的服务进行合同测试,并根据第 8 章《测试微服务架构》中描述的最佳实践设计我们的微服务架构。

  3. 重视并优先考虑代码质量:作为一个组织,您应该重视并优先考虑代码质量,允许工程团队有时间重构他们的服务,以确保它们可以轻松扩展和维护以满足未来的业务需求。

  4. 记录非功能需求:虽然测试的一个重要用途是确保我们的系统能够满足功能需求,但另一个重要方面是根据客户需求验证系统的性能。我们在第 2 章《单元测试要点》中探讨了如何使用基准测试来测试代码的性能。

最后要记住的一点是,没有完美的测试策略,因为它无法涵盖每个代码路径和边缘情况。我们在本书中探讨的工具和技术应该帮助您规划和实施系统的有效测试。测试策略没有 “一刀切” 的方法,因此请确保您与产品经理和其他关键业务利益相关者合作,以确保您的测试工作高效进行。