go test -coverprofile 覆盖率虚高是因为默认排除_test.go、vendor/、条件编译块和注释代码,导致统计分母缩小;应过滤路径后用-coverpkg显式指定包路径。

go test -coverprofile 为什么总显示虚高数字
因为默认统计范围排除了 _test.go、vendor/、条件编译块(如 //go:build ignore)和注释行,分母被人为缩小。比如你写了 100 行业务代码,但其中 20 行被注释或在 vendor 里,覆盖率就按 80 行算——哪怕只测了 40 行,也显示 50%,实际覆盖才 40%。
- 用
go list ./ | grep -v /vendor/ | grep -v _test.go过滤出真实参与构建的包路径,再传给-coverpkg - 显式加
-coverpkg=./(或具体子包路径如-coverpkg=./handler,./service),避免跨包依赖漏统计 - 别信终端里
coverage: 87.2% of statements这一行总览,它掩盖了handler.Login只有 12% 覆盖的事实
HTTP 集成测试怎么让 main 和 handler 被覆盖率捕获
单元测试跑 httptest.NewRecorder 永远测不到 main()、中间件初始化、DB 连接池启动这些路径。必须启动真实 http.Server,但直接 import main 会报错。
- 把
main()里的逻辑拆出来:暴露server.Handler变量或server.NewServer(addr string)函数 - 测试中用
srv := server.NewServer("127.0.0.1:0")启动,srv.ListenAndServe()放 goroutine 里,避免阻塞 - 用真实
http.Client发请求,不是httptest.NewRequest - 启动前加
os.Setenv("GOCOVERDIR", "coverage")(Go 1.21+),或老版本用-coverprofile=coverage.out+go tool cover合并
mock 接口时 error 分支不触发的根本原因
你写了 mockDB.EXPECT().QueryRow(...).Return(nil, nil),但真实逻辑里有 if err != nil { return err } —— 这个分支永远红着,因为 mock 没返回 error。
- 每个外部调用至少写两条期望:一条成功(
Return(row, nil)),一条失败(Return(nil, sql.ErrNoRows)或errors.New("timeout")) - 对缓存 → DB 的组合路径(如先
cache.Getmiss 再db.QueryRow),要分别 mockcache.Get返回nil,再 mockdb.QueryRow返回 error - 测试末尾必须加
mockCtrl.Finish()或mock.AssertExpectations(t),否则期望没设全也会“PASS”
CI 中 go test 怎么写才不 flaky
本地通过的测试,在 CI 里超时、panic、连接拒绝,90% 是环境假设崩了:数据库没启、端口被占、临时目录不可写、Go 版本差异触发新 panic。
- 加
-timeout=60s防挂起,尤其含 HTTP client 或 DB 连接的测试 - 强制
-p=1禁用并行,排除竞态干扰 - 始终带
-v输出日志,失败时能快速定位是哪个TestXXX卡住 - 禁用
log.Fatal和os.Exit(1)—— 它们会跳过断言收集,CI 显示 “PASS” 实际已中断 - 用
grep -q 'total.*[8-9][0-9]\.[0-9]%' coverage.out || exit 1卡住低覆盖提交,别只看数字,重点看 error path 是否被覆盖
context.WithCancel 后立刻 cancel()、有没有 mock 出 io.EOF 触发重试逻辑、有没有让 config.Load() 返回 os.IsNotExist 错误——这些才是线上崩溃前最后几行没被测到的代码。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











