第一个能跑通的go测试函数需满足:文件名以_test.go结尾、与被测代码同包、函数名为testxxx且参数为testing.t;例如func testadd(t testing.t) { got := add(2,3); want := 5; if got != want { t.errorf("add(2,3) = %d, want %d", got, want) } }。

怎么写第一个 go test 能跑通的测试函数
Go 的测试不是靠第三方库,而是语言原生支持——只要文件名以 _test.go 结尾、函数名以 Test 开头、参数是 *testing.T,就能被 go test 自动发现。
常见错误:把测试函数写成 func testAdd()(没大写、没参数)、或者放在 main.go 里(没加 _test 后缀),go test 直接静默跳过,不报错也不运行。
- 测试文件必须和被测代码在同一个包下(比如
calc.go和calc_test.go都在main包) - 函数签名必须是
func TestXxx(t *testing.T),少一个星号或换个参数名都不行 - 运行命令就是
go test(当前目录)或go test ./...(整个模块)
示例:add.go 里有 func Add(a, b int) int { return a + b },对应测试写在 add_test.go:
func TestAdd(t *testing.T) {
got := Add(2, 3)
want := 5
if got != want {
t.Errorf("Add(2,3) = %d, want %d", got, want)
}
}
t.Fatal 和 t.Error 到底该用哪个
区别不在“严重程度”,而在“是否继续执行”:用 t.Error 会记录失败但跑完所有断言;t.Fatal 一触发就立刻终止当前测试函数,后续语句不执行。
立即学习“go语言免费学习笔记(深入)”;
典型误用:在循环里对每个元素做检查,却用了 t.Fatal——结果第一个失败就停了,后面几十个 case 全被跳过,误以为“只有一处问题”。
- 单个断言后还想继续验证其他逻辑 → 用
t.Error - 前置条件不满足(比如文件打不开、依赖服务连不上)→ 用
t.Fatal快速退出 - 想提前返回又不想写
return?不行。t.Fatal不会自动 return,必须自己跟一句return
为什么 go test 什么都没输出,像没跑一样
默认情况下,go test 只在测试失败或显式调用 t.Log/t.Logf 时才打印内容。全绿通过时,它真的就只输出 ok ... 0.001s ——这不是卡住,是设计如此。
容易踩的坑:以为测试没运行,其实是通过了;或者调试时加了 fmt.Println,结果被测试框架屏蔽(fmt 输出不进测试日志)。
- 想看每轮测试的中间值 → 改用
t.Log("value:", x) - 想强制看到所有测试名称和耗时 → 加
-v参数:go test -v - 想看覆盖率 →
go test -cover,但注意它只统计被测试代码行,不包括if false { ... }这类死代码
测试私有函数(未导出函数)要改名或拆包吗
不用。Go 的测试文件和源文件在同一包内,能直接访问所有标识符,包括小写开头的函数、变量、结构体字段。
常见误解:觉得“私有=不能测”,于是把 parseConfig 改成 ParseConfig 暴露出去,反而破坏封装。其实只要它们在同一个 package xxx 下,测试就能调。
- 被测函数是
func parseLine(s string) (int, error)→ 测试里直接调parseLine("123") - 唯一例外:跨包测试(比如想测
internal/xxx里的函数),那确实需要重构——但那是架构问题,不是测试技术问题 - 如果私有函数逻辑太重、难以构造输入,优先考虑的是提取纯函数或改接口,而不是暴露它
真正容易被忽略的是测试边界:比如空字符串、负数、超长输入、并发调用。这些不会因为函数“私有”就自动绕开,得手动覆盖。










