testify/assert.panics用于检测代码是否panic,需传入无参函数,不捕获goroutine内panic;panicswithvalue可校验panic值,但类型严格;手动recover更灵活但易出错,需注意panic(nil)和defer顺序。

测试 panic 是否发生:用 testify/assert.Panics 最直接
想确认某段 Go 代码真的会 panic,而不是静默失败或返回错误,testify/assert.Panics 是最常用也最省事的选择。它本质是 recover + defer 的封装,帮你捕获 panic 并比对是否触发。
常见错误现象:assert.Panics(t, func() { /* 没有 panic 的函数 */ }) 会直接失败,但错误信息只说 “Expected function to panic”,不告诉你实际发生了什么——容易误以为测试写错了,其实是被测函数没按预期 panic。
- 必须传入一个无参、无返回的函数(
func()),不能直接传调用结果(比如assert.Panics(t, foo())) - 如果被测函数需要参数,得用闭包包裹:
func() { foo("x", 42) } - 它不检查 panic 的具体值(比如 panic("bad input") 和 panic(123) 都算“panic 发生了”),要验内容得用
assert.PanicsWithValue - 底层依赖
recover(),所以不能在 goroutine 里直接测——panic 发生在子 goroutine 中时,主 goroutine 的 recover 捕不到
验证 panic 的具体内容:优先用 assert.PanicsWithValue
很多场景下,“有没有 panic”不够,你得确认 panic 的值符合预期,比如是否 panic 了特定错误字符串、某个自定义 error 类型,或者 nil。
使用场景:API 校验逻辑中主动 panic(fmt.Errorf("invalid id: %s", id)),测试就得确保 panic 值包含 "invalid id"。
立即学习“go语言免费学习笔记(深入)”;
家电公司网站源码是一个以米拓为核心进行开发的家电商城网站模板,程序采用metinfo5.3.9 UTF8进行编码,软件包含完整栏目与数据。安装方法:解压上传到空间,访问域名进行安装,安装好后,到后台-安全与效率-数据备份还原,恢复好数据后到设置-基本信息和外观-电脑把网站名称什么的改为自己的即可。默认后台账号:admin 密码:132456注意:如本地测试中127.0.0.1无法正常使用,请换成l
-
assert.PanicsWithValue(t, "invalid id", func() { parseID("") })—— 字符串字面量匹配(用==比较) - 若 panic 值是 error 类型,且你想用
errors.Is或errors.As判断,得改用assert.PanicsWithPattern或手写 recover - 注意类型精度:panic 一个
fmt.Errorf("x")和 panic 一个"x"字符串,前者是 *fmt.wrapError,后者是 string,PanicsWithValue会严格按类型+值匹配,不自动转换 - 空值要显式写
nil:assert.PanicsWithValue(t, nil, func() { panic(nil) })
无法用 testify 的情况:手动 recover 更可控
当你要测的 panic 发生在 goroutine 里,或者需要 inspect panic 值的结构(比如断言它实现了某个 interface),testify/assert 就力不从心了——它只做黑盒捕获,不暴露 recover 出来的值。
性能 / 兼容性影响:手动 recover 没额外依赖,Go 1.0+ 都支持;但写法稍啰嗦,容易漏 defer 或 recover 顺序出错。
- 必须把
defer+recover()写在 panic 可能发生的同一 goroutine 中 - 典型结构:
var r interface{}<br>defer func() { r = recover() }()<br>foo() // 可能 panic<br>assert.NotNil(t, r) - recover 返回
interface{},需类型断言才能进一步判断:assert.Equal(t, "boom", r.(string)),但要注意 panic(nil) 时r是 nil,断言会 panic - 如果被测函数本身可能返回 error 而不是 panic,记得在 recover 后补上正常 error 检查逻辑,避免漏掉非 panic 错误路径
容易忽略的边界:panic(nil) 和 recover 的时机
Go 允许 panic(nil),这很特殊:它确实触发 panic 流程,但 recover() 拿到的是 nil,不是 interface{}(nil)。很多人误以为 “recover 返回 nil 就代表没 panic”,其实不然。
另一个坑是 defer 执行顺序:如果多个 defer 都调用 recover,只有第一个能拿到 panic 值,后面的都得到 nil——所以别在多个地方乱加 recover。
-
assert.Panics能捕获panic(nil),但assert.PanicsWithValue(t, nil, ...)也能通过,这点反而比手动 recover 更直观 - 测试并发代码时,务必确认 panic 是在当前 goroutine 触发的;否则即使写了 recover,也捕不到
- 如果函数内部用了
log.Fatal或os.Exit,它们不会触发 panic,recover完全无效——这种得用os/exec启子进程测,不属于 panic 测试范畴
panic 测试真正难的不是语法,而是厘清 panic 发生的 goroutine 层级和 recover 的作用域边界。写完别急着提交,用 go test -v 看一眼 panic 输出是不是真从被测函数里冒出来的。









