go test -cover 显示 0.0% 表示测试未被识别或执行,主因是_test.go 文件名不规范、测试函数签名错误(非 func TestXxx(t *testing.T))、未在被测包目录下运行命令;需先用 go test -v 确认有 === RUN TestXXX 输出,再通过 -coverprofile=coverage.out -covermode=count 生成覆盖率文件,用 go tool cover -func 或 -html 分析,注意红色为未覆盖(需补测 error/context/nil 分支),灰色为不可执行代码(无需处理)。

go test -cover 显示 0.0% 是没跑测试,不是覆盖率低
执行 go test -cover 看到 coverage: 0.0% of statements,基本可以确定测试根本没被识别或执行。这不是代码难测,是测试基础设施没搭对。
-
_test.go文件名必须严格以_test.go结尾(如service_test.go✅,service_tests.go❌) - 测试函数必须以
Test开头且签名是func TestXxx(t *testing.T)(func checkLogin()或func TestLogin()缺少t *testing.T参数都不行) - 必须在**被测代码所在包目录下**运行命令(比如
internal/service/里的代码,就要 cd 进去再go test -v;在项目根目录只跑go test -cover ./可能跳过子包) - 先用
go test -v确认输出里有=== RUN TestXXX—— 没这行,后面所有覆盖率数字都是无效的
生成 coverage.out 才是分析函数级覆盖率的唯一起点
go test -cover 只输出一个笼统百分比,无法定位哪个函数、哪行语句漏了。真正要查函数覆盖,必须生成 profile 文件。
- 正确命令:
go test -coverprofile=coverage.out -covermode=count .(注意=不能省,.表示当前包;多子包项目用./...或加-coverpkg=./) -
coverage.out是二进制文件,cat不出内容,也别提交进 Git(加进.gitignore) - 立刻验证:运行
go tool cover -func=coverage.out,它会按函数列出覆盖率,重点关注0.0%、33.3%、50.0%这类值——它们通常对应未触发的else、if err != nil、defer块 - 别用默认的
set模式(只记“是否执行过”),-covermode=count能记录执行次数,对分支覆盖判断更准
go tool cover -html 必须通过 HTTP 访问,双击打开必空白
生成的 coverage.html 是动态渲染的,现代浏览器禁用 file:// 协议下的 JS 执行,所以双击或拖入浏览器一定空白。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 推荐做法:直接运行
go tool cover -html=coverage.out,它会自动起本地服务(默认端口59090),浏览器打开http://localhost:59090即可 - 备用做法:在当前目录运行
python3 -m http.server 8000,然后访问http://localhost:8000/coverage.html - 绝对不要移动
coverage.out或 HTML 文件位置——Go 记录的是源码绝对路径,路径错一点就报open xxx.go: no such file or directory - 看懂颜色:
绿色= 执行 ≥1 次,红色= 完全未执行(重点补测对象),灰色= 不可执行代码(空行、注释、函数签名等,不参与统计,不用管)
函数覆盖率低往往卡在 error 分支、context 取消和 nil/空切片差异上
很多函数显示 0.0% 或 50.0%,不是逻辑复杂,而是测试没主动构造失败路径。
立即学习“go语言免费学习笔记(深入)”;
- 对每个返回
error的外部调用,mock 至少定义两条行为:mock.On("GetUser").Return(user, nil)和mock.On("GetUser").Return(nil, errors.New("timeout")) - HTTP handler 测试中,用
httptest.NewRequest("POST", "/api", bytes.NewReader([]byte("")))触发json.Decode失败;别只用nilbody - 注意
var s []string = nil和s := []string{}的区别:二者len(s) == 0都为 true,但某些分支(如if s == nil)行为不同,都要覆盖 - 带
context.Context的函数,测试必须传已cancel()的 ctx 来触发超时路径,别用time.Sleep等真实时间

















