测试 recover 行为必须在 defer 内部调用 recover(),直接在测试函数中调用永远返回 nil;需在 defer 中捕获 panic 值并验证其类型与内容,子 goroutine 的 panic 无法被外层 recover 捕获,调试时优先使用 runtime/debug.stack()。

测试 recover 行为必须在 defer 内部调用 recover()
直接在测试函数里写 recover() 永远返回 nil,因为 panic 已结束、调用栈已 unwind 完毕。测试 recover 是否生效,本质是测试「defer 中的 recover 是否捕获到 panic 值」。
- ✅ 正确姿势:测试函数中先注册
defer func() { r := recover(); ... }(),再触发 panic - ❌ 错误写法:
func TestX(t *testing.T) { panic("boom"); r := recover() }——recover()根本不会执行 - ⚠️ 注意:
recover()返回值类型是interface{},断言前需先判空,再做类型转换(比如r.(string)或r.(error))
用 reflect.TypeOf() 或类型断言验证 panic 值类型
panic 可以传任意值:panic("msg")、panic(errors.New("x"))、panic(struct{Code int}{404})。测试时若只检查 r != nil 不够严谨,容易漏掉类型不匹配的逻辑分支。
- 推荐先用
assert.NotNil(t, r),再用assert.Equal(t, "expected", r)(适用于 string) - 若 panic 传的是 error,应显式断言:
err, ok := r.(error); assert.True(t, ok); assert.Equal(t, "xxx", err.Error()) - 避免直接
r.(error)强转——panic 值不是 error 时会 panic,导致测试崩溃而非失败
子 goroutine 的 panic 无法被外层测试 recover 捕获
写单元测试时,如果被测函数内部启动了 goroutine 并 panic,主 goroutine 的 defer + recover 完全无效。测试会卡住、超时,或直接 panic 退出。
- 现象:
go func() { panic("in goroutine") }()导致测试进程崩溃,且无堆栈输出 - 解决方法:要么把 goroutine 逻辑抽出来单独测(不启 goroutine),要么在 goroutine 内部加
defer func(){ recover() }() - 真实场景常见于 HTTP handler、worker pool —— 测试时务必模拟同构执行环境,不能依赖“外面包一层 defer 就万事大吉”
runtime/debug.Stack() 是调试 recover 失效的唯一可靠手段
当测试中 recover() 返回 nil 但你确认 defer 在 panic 前注册了,大概率是 panic 发生在别的 goroutine,或 recover 调用时机不对(比如 defer 函数里又 panic 了)。
- 在 defer 函数里加
buf := make([]byte, 2048); runtime.Stack(buf, false),打印完整堆栈,确认 panic 真实发生位置 - 注意:
runtime.Stack()第二个参数为false时只输出当前 goroutine;设为true会输出全部 goroutine,日志爆炸,慎用 - 别依赖
fmt.Printf或t.Log——panic 后 stdout 可能未 flush,日志丢失;优先用t.Errorf或直接写文件
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











