go语言中`testing.m`的`recover`为何无法捕获测试函数中的panic,根本原因是go测试框架将每个`testxxx`函数在独立goroutine中执行,而`recover`只能捕获**当前goroutine**内发生的panic,无法跨goroutine生效。
在Go的测试机制中,TestMain(m *testing.M)运行于主goroutine,负责初始化、全局设置及最终退出控制;而所有TestXxx函数(如TestSomeTest)均由m.Run()内部调度,在新启动的goroutine中并发执行。由于Go的panic/recover机制具有严格的goroutine边界性——recover()仅能拦截同一goroutine中由panic()触发的、且尚未被其他recover处理过的异常——因此在TestMain主goroutine中设置的defer+recover对子goroutine中发生的panic完全无效。
这与以下代码行为一致:
func TestGoroutinePanic(t *testing.T) {
defer func() {
if r := recover(); r != nil {
fmt.Println("❌ This will NOT print")
}
}()
go func() {
panic("panic in goroutine") // → 无法被外层recover捕获
}()
time.Sleep(10 * time.Millisecond) // 确保goroutine执行
}
该测试会直接崩溃并输出panic: panic in goroutine,证明跨goroutine panic不可恢复。
✅ 正确做法:每个测试函数需自行处理panic(若需捕获),例如: