Go语言单元测试需满足五要素:文件名以_test.go结尾、函数名以Test开头且首字母大写、参数为*testing.T、与被测代码同包、接口抽象+依赖注入;否则测试静默跳过或编译失败。

Go 语言没有“框架接口”这种内置概念,所谓“框架接口单元测试”,本质是测你自己定义的接口(interface{})及其具体实现,再通过依赖注入让业务逻辑可被隔离验证。不抽象出接口、不注入依赖,就根本没法写真正可靠的单元测试。
Test函数必须以Test开头且参数为*testing.T
这是go test能识别并运行测试的硬性门槛。漏掉任意一条,测试会静默跳过——不是报错,是压根不执行。
- 文件名必须是
_test.go结尾,比如user_service_test.go - 函数名必须是
TestXxx格式,首字母大写,例如TestUserService_Login,testUserServiceLogin或Testlogin都无效 - 参数类型必须严格是
*testing.T,写成*testing.B(性能测试)或testing.T(少指针)都会编译失败或被忽略 - 测试函数必须和被测代码在同一个包里,否则无法访问未导出方法或字段
接口抽象 + 依赖注入才是可测性的前提
直接在函数里调用http.DefaultClient.Do或db.QueryRow,测试时就会连真实网络或数据库,既慢又不稳定,还无法控制返回值。必须提前把依赖抽成接口,并作为参数传入。
- 定义接口,比如
type UserRepository interface { GetUser(id int) (*User, error) } - 业务函数接收该接口,而非具体实现:
func (s *UserService) Login(repo UserRepository, username string) error - 测试时构造一个 fake 实现:
type fakeRepo struct{},只实现GetUser并返回预设数据 - 避免用第三方 mock 工具生成复杂 mock 对象;简单 fake 更可控,也更贴近真实行为
表驱动测试(Table-Driven Tests)是覆盖多场景的标配写法
手写一堆TestXxx1、TestXxx2不仅冗余,还容易漏掉边界条件。用切片组织输入/期望/错误,循环跑,结构清晰、易维护。
立即学习“go语言免费学习笔记(深入)”;
- 每个子测试用
t.Run包裹,名字带上下文,如t.Run("valid_user", func(t *testing.T) { ... }) - 注意闭包陷阱:循环变量
tt要在range内显式拷贝,否则所有子测试共享最后一个值 - 错误信息里带上
tt.name和实际值,失败时一眼定位哪条 case 挂了 - 不要在表里塞太多逻辑,比如动态计算
expected;预设值越静态,测试越稳定
go test命令常用参数与陷阱
go test本身极简,但参数组合不对,就看不到真实问题。
-
go test:只跑当前目录下所有*_test.go里的Test*函数 -
go test -v:显示每个测试函数的t.Log和失败详情,没加它等于盲测 -
go test -run=TestUserService_Login:精准运行单个函数,改完立刻验证,别全量跑 -
go test -coverprofile=c.out && go tool cover -html=c.out:覆盖率报告只反映“是否执行”,不保证逻辑正确;0% 覆盖说明漏写了测试,100% 覆盖也不代表没 bug - 别在
init()里做初始化操作——它会在所有测试前执行一次,导致状态污染
最常被忽略的点是:测试文件和被测代码不在同一包,或接口没抽象、依赖没注入。这两条不满足,后面所有技巧都是空谈。先让go test -v能跑通一个最简 fake 测试,再往上加逻辑和覆盖场景。


















