
大家好,我是Tony Bai。
欢迎来到《Go 测试之道:从测试金字塔到高级实践》的第二讲。
在上一讲中,我们成功地为我们“短链接”项目的 validator 包编写了第一个单元测试。那是一次愉快的“热身”,因为我们测试的是一个纯函数——它没有外部依赖,没有副作用,给定相同的输入,永远返回相同的输出。
但真实世界的软件,远比这复杂。今天,我们将正式踏入这片“复杂地带”,深入项目的核心——service 业务逻辑层。在这里,我们的代码将不可避免地需要与外部世界(如数据库、缓存)交互。
这立刻给我们带来了巨大的挑战:在一个隔离的、快速的单元测试环境中,我们该如何处理这些“烦人”的外部依赖?
解决这个问题的能力,是区分初级和资深工程师的关键分水岭。在本讲,我们将不再满足于只写一个简单的测试函数,而是要系统性地构建我们的单元测试思维框架。我们将一起探索测试的“形状”,从三个维度来解构它:
组织的形状: 一个测试套件(Test Suite)和多个测试用例(Test Case)应该如何组织?
生命周期的形状: 如何管理测试开始前的准备(Setup)和结束后的清理(Teardown)?
视角的形状: 我们的测试代码应该站在哪里,是深入内部(白盒),还是守护外部(黑盒)?
在厘清了这些“形状”之后,我们才会去正面迎战最核心的挑战——处理外部依赖。我将为你揭示测试替身 (Test Doubles) 的奥秘,并手把手带你实现一个健壮的 Fake Object。
本讲内容密度会比较大,但请相信,一旦掌握了这些核心思想和实践,你编写单元测试的能力将发生一次质的飞跃。让我们开始吧!

第一部分:单元测试的“道”——理论武装你的大脑
在动手之前,我们必须先建立起正确的认知。我将为你介绍 Go 单元测试的“四梁八柱”:如何组织用例、如何选择视角、如何处理依赖,以及如何精通工具(尤指关于testing.T的一些使用技巧)。
测试的“形状”之一:如何组织你的测试用例与测试套件?
首先,我们来探讨一个看似简单却至关重要的问题:在 Go 语言的语境下,究竟什么才是一个“测试用例” (Test Case) 和 “测试套件” (Test Suite)?
很多来自其他语言的开发者会寻找类似 JUnit 或 PyTest 中显式的 @TestSuite 注解,但在 Go 的原生测试框架中,这些概念是以一种更简洁、更符合惯例的方式存在的。
测试用例 (Test Case): 在 Go 中,一个理想的、现代的测试用例,应该是一个独立的、可命名的、可单独运行的执行单元。它精确地对应着对被测对象某一个特定场景或行为的一次验证。在实践中,它通常就是由子测试 (
t.Run) 驱动的、表驱动测试中那张“表”里的一行数据。测试套件 (Test Suite): 在 Go 中,并没有一个名为
TestSuite的原生类型,但我们可以将一个顶层的TestXxx(t *testing.T)函数 视作一个事实上的“测试套件”。它的职责就是组织和运行一组相关的测试用例(即t.Run创建的子测试)。
让我们用一张更新后的图来将这个心智模型固化下来:

被折叠的 条评论
为什么被折叠?



