Go测试函数名必须以Test开头,Example函数名必须以Example开头;Test函数接收testing.T或testing.B,用于断言和性能测试,而Example函数仅可选接收*testing.T,用于文档示例与输出校验,需严格匹配// Output:注释。

Go测试函数名必须以Test开头,Example函数名必须以Example开头
这是最直接的区分点。Go的go test命令只识别func TestXxx(*testing.T)格式的测试函数;而示例代码(Example)是用于生成文档和验证可运行性的特殊函数,必须命名为ExampleXxx,且参数和返回值有严格限制——只能无参或仅接收*testing.T,不能有其他参数,也不能返回值。
常见错误是把示例写成func ExampleFoo() { ... }却忘了导出首字母大写,或者误加error返回值导致go test直接忽略该函数。
-
Test函数:必须接收*testing.T或*testing.B,用于断言、性能基准等 -
Example函数:可选接收*testing.T(用于失败时标记示例失效),但不支持*testing.B - 未导出的
example函数(如exampleHelper())不会被go doc或go test -run=Example识别
Example函数会被go doc提取为文档示例,且自动验证是否能编译+运行
当你运行go doc fmt.Print,看到的“Example”区块就来自源码中名为ExamplePrint的函数。Go工具链在生成文档时会解析这些函数,并在go test中用-run=Example单独执行它们——不仅检查是否编译通过,还会比对函数末尾的// Output:注释与实际标准输出是否完全一致(包括空格和换行)。
这意味着:Example既是文档,也是测试,但约束更强:输出必须可预测、不可含随机值(如time.Now())、不可依赖外部状态。
- 必须在函数末尾添加
// Output:注释,否则go test -run=Example会报错missing output comment - 输出内容需字面量匹配,例如
fmt.Println("hello")对应// Output: hello(注意末尾换行) - 若使用
t.Log或t.Error,不会影响// Output:校验,但会影响示例是否“通过”
func ExampleParseInt() {
n, err := strconv.ParseInt("42", 10, 64)
if err != nil {
panic(err)
}
fmt.Println(n)
// Output: 42
}
Example不能像Test那样使用t.Helper()或子测试t.Run()
*testing.T在Example中功能受限。虽然可以传入并调用t.Fatal、t.Log,但t.Helper()、t.Run()、t.Cleanup()等方法在Example上下文中不生效,调用会 panic 或静默失败。
根本原因是Example不是为“组织测试逻辑”设计的,而是为“展示典型用法 + 验证输出”服务的。它没有测试生命周期管理需求,也不支持并发子示例。
- 不要在
Example里写多个场景——应拆成ExampleXxx_Basic、ExampleXxx_ErrorCase等独立函数 - 避免在
Example中做资源清理(如os.Remove),因为失败时无法保证执行 - 若需复用逻辑,用普通未导出函数(如
parseAndPrint()),但确保它不依赖t或产生非确定输出
go test -run=Example只运行Example函数,但默认不运行
很多人以为go test会自动跑Example,其实不会——除非显式指定-run=Example或使用-run='^Example.*$'。这也是容易忽略的关键点:Example代码可能长期没被执行,直到某次文档生成或手动验证才发现已失效。
CI中若想保障示例始终有效,必须在测试命令中加入go test -run=Example ./...。另外,go test -v -run=Example会显示每个Example的输出对比结果,便于调试不匹配问题。
-
go test默认只运行Test函数 -
go test -run=Example只运行Example函数(当前包) -
go test -run=ExampleXXX可精确匹配函数名,比如go test -run=ExampleJSONMarshal
// Output:和代码脱节,go doc展示的就是过期示例——这种问题往往在线上被用户第一个发现。










