go test ./ 仅递归测试当前模块内所有包,无法覆盖多 go.mod 子模块;正确做法是用 find . -name "go.mod" -exec dirname {} \; 列出各模块路径并分别执行 go test -v ./...,确保每个独立模块的测试都被触发。

用 go test ./ 覆盖所有子模块,而不是只跑主包
很多团队只在根目录执行 go test ./... 或 go test ./,但实际只会运行当前模块下的测试——如果项目含多个独立 go.mod(如 service-auth/、service-payment/),这些子模块的测试根本不会被触发。结果是:依赖升级后,子模块里早已存在的类型不匹配或方法缺失完全没暴露。
正确做法是显式遍历每个子模块目录并单独运行测试:
- 先用
find . -name "go.mod" -exec dirname {} \;列出所有含go.mod的路径 - 对每个路径执行
cd $path && go test -v ./... - CI 中建议写成循环脚本,避免漏掉新加入的模块
检查 go list -m all + go mod graph 是否出现意外版本跳升
升级后看似编译通过,但某个间接依赖可能从 v0.5.1 跳到了 v0.6.0,而这个 v0.6.0 悄悄改了未导出字段的结构体布局——你的代码若用了反射或 unsafe.Pointer,就会在运行时 panic。这类问题 go build 不报错,go test 也未必覆盖到。
必须人工核对两个命令输出:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
-
go list -m all:确认每个模块是否落在预期主版本内(比如golang.org/x/net仍为v0.17.x,而非升到v0.20.x) -
go mod graph | grep 'x/net':查清是谁引入了新版,是直接依赖升级带进来的,还是某二级依赖悄悄升级了 - 特别注意伪版本(如
v0.0.0-20240512102345-abc123)——它可能来自未打 tag 的 dev 分支,稳定性无保障
契约测试要覆盖接口实现,不能只测 mock
当模块 A 依赖模块 B 提供的 UserClient 接口,很多人只给 A 写单元测试,用 mock 实现该接口。这只能验证 A 的逻辑,无法发现 B 的真实实现是否因依赖升级而破坏契约——比如 B 升级后,GetUser 开始返回 nil 而不是错误,或字段名大小写变了。
契约测试必须用真实实现跑一遍:
- 在
integration-tests/模块中,构造真实UserClient(连本地服务或内存 mock server) - 调用
RunUserClientTests(t, client)——这个函数应定义在接口所在模块,所有实现都复用同一套断言 - 每次依赖升级后,这个测试必须重新过,否则“兼容”只是假象
replace 指令会掩盖真实兼容性问题
开发时常用 replace github.com/foo/bar => ./local/bar 来调试,但它会让 go build 和 go test 绕过远程版本,导致你根本不知道升级后的官方版本是否真能跑通。更糟的是,CI 环境没配 replace,构建直接失败。
处理原则很明确:
- 本地联调允许用
replace,但提交前必须删掉或注释掉 - 真正验证兼容性,必须基于 clean 的
go.mod(无replace、无exclude)执行完整测试流 - 如果删掉
replace后测试挂了,说明上游还没兼容——这不是你项目的问题,而是升级时机不对
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










