go test -coverprofile 覆盖率不准因默认排除 _test.go、vendor/、条件编译块及注释代码,导致分母缩小、虚高;应过滤后生成 profile 并用 -coverpkg=./... 显式指定包路径。

go test -coverprofile 生成的覆盖率数据为什么不准
因为默认会把 _test.go 文件、vendor/ 目录、条件编译块(如 //go:build ignore)和注释掉的代码都排除在统计分母外,导致“虚高”。真正该看的是参与构建的实际业务代码。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 用
go list ./... | grep -v /vendor/ | grep -v _test.go过滤后生成 profile,更贴近真实覆盖范围 - 加
-coverpkg=./...显式指定要统计的包路径,避免跨包依赖漏统计 - 别信
go test -cover输出的总百分比,它掩盖了 handler 函数 20% 覆盖、工具函数 100% 的严重不均衡
mock 接口时为什么 error 分支永远不进
因为你只写了 mock.On("Get").Return(user, nil),没写失败路径。Go 的错误分支是显式分支,不会“顺便”触发——它必须被构造出来,否则那几行 if err != nil { log.Fatal() } 就永远红着。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 每个外部调用至少 mock 两条:一条成功,一条明确返回
errors.New("timeout")或sql.ErrNoRows - 对
cache.Get和db.QueryRow这类组合路径,要分别 mock cache miss → db error 场景,不能只测单点成功 - 在测试末尾加
mock.AssertExpectations(t),防止期望没设却误判通过
带 context 的超时/取消逻辑怎么稳定触发
靠 time.Sleep 等超时既慢又不可靠,CI 上还容易 flaky。真正可控的方式是主动控制 context 状态。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 测试取消:用
ctx, cancel := context.WithCancel(context.Background()); cancel(),再传入函数 - 测试超时:用
ctx, _ := context.WithTimeout(context.Background(), 1*time.Millisecond),确保 select 中的 timeout case 必然命中 - 表格驱动测试里单独设字段,比如
{"ctx cancelled", buildCancelledCtx(), true},让覆盖率 HTML 能直接定位到该分支
nil 切片和空切片为什么必须分开测
因为 len(s) == 0 成立时,s == nil 不一定成立;而很多 JSON 解码、数据库 scan、map range 场景下,二者行为完全不同——前者 panic,后者只是跳过循环。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 构造
var s []string = nil和s := []string{}两种输入,分别跑测试 - HTTP handler 测试中,用
bytes.NewReader([]byte(`{"items":null}`))触发 nil slice 解析 - 查
go tool cover -func=cover.out输出,重点关注那些只覆盖了len > 0却漏掉nil分支的函数
if err != nil、ctx.Err() != nil、s == nil 这些分支是否真被执行过——它们往往藏在 defer、log.Fatal 或 panic 里,一漏就是线上事故。

















