不能用panic模拟接口异常做容灾测试,因panic是程序崩溃信号,会绕过真实的if err != nil错误处理分支,导致测试失效;正确做法是用mock.return()返回具体error值,触发重试、降级等容错逻辑。

不能也不该用 panic 模拟接口异常做容灾测试。 容灾逻辑要验证的是对 error 的响应,而 panic 是程序级崩溃信号,两者语义和处理路径完全不同。强行用 panic 会绕过你真实业务中写的 if err != nil 分支,测了等于没测。
为什么 mock 接口时 panic 是危险信号
gomock、testify/mock 等工具设计目标是模拟接口方法的 return 值,包括 nil 和具体 error。一旦你在 mock 中调用 panic(比如 mockSvc.EXPECT().Do().Do(func() { panic("boom") })):
- 测试会立即中断,无法进入你写好的错误重试、降级或熔断逻辑
- recover 捕获的是 test goroutine 的 panic,不是业务调用链中的 error 流程
- 真实微服务调用失败时,HTTP client 返回的是
err != nil,不是 panic - CI 环境下 panic 可能被全局 recover 吞掉,导致测试“假通过”
正确做法:用 error 模拟所有可预期失败
容灾测试的关键是让下游返回你想要的 error,触发上游的容错分支。gomock 中必须用 .Return() 显式设定:
- 网络超时:
mockSvc.EXPECT().GetUser(gomock.Any()).Return(nil, &net.OpError{Op: "read", Net: "tcp", Err: os.ErrDeadlineExceeded}) - HTTP 503:
mockSvc.EXPECT().PostOrder(gomock.Any()).Return(nil, &url.Error{Op: "post", URL: "/order", Err: errors.New("503 Service Unavailable")}) - JSON 解析失败:
mockSvc.EXPECT().FetchConfig(gomock.Any()).Return(nil, errors.New("invalid character 'x' looking for beginning of value"))
注意:不要只写 .Return(nil, nil) 或 .Return(nil, errors.New("")) —— 空错误字符串会让 errors.Is(err, xxx) 判断失效,掩盖真实容错逻辑。
需要测 panic 场景?只限于程序崩溃防护本身
如果你真要验证「某个函数内部 panic 后,外层是否被 recover 住」,那属于 crash protection 测试,不是容灾测试。此时应:
- 把可能 panic 的逻辑包进独立函数,例如
func riskyParse(data []byte) (int, error) - 在测试中手动触发 panic:
defer func() { recover() }(); riskyParse([]byte{0xff}) - 检查 recover 是否捕获到预期类型(如
*json.SyntaxError),而不是检查业务状态 - 这类测试必须加
// +build unit标签隔离,禁止混入集成测试流程
真正的容灾能力,永远建立在 error 的显式传播与分层处理上。mock 返回 panic 不是在测容灾,是在制造不可控的测试噪声。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











