如何使用testify断言logrus触发Panic时的错误消息?
使用Logrus时用Testify断言Panic的Message内容
问题场景
使用Logrus日志库时,通过mylogger.Panic()抛出panic,尝试用Testify的PanicsWithError断言panic内容时失败——捕获到的panic值是Logrus的Entry对象,而非预期的错误字符串。
业务代码示例
var mylogger = logrus.WithContext("MyLogger") func LoadPreparedStatements() { db := psql.PsqlClient() var err error myPreparedStatement, err = db.Prepare("SELECT * FROM mytable") if err != nil { mylogger.Panic("Loading SQL Prepared Statement Failed") } }
测试代码尝试
PanicsWithError(t, "test", func() { LoadPreparedStatements() })
捕获到的Panic值
Panic value: &logrus.Entry{Logger:(*logrus.Logger)(0xc0000ba000), Data:logrus.Fields{"context":"MyLogger"}, Time:time.Date(2022, time.November, 1, 21, 49, 27, 889501622, time.Local), Level:0x0, Caller:(*runtime.Frame)(nil), Message:"Loading SQL Prepared Statement Failed", Buffer:(*bytes.Buffer)(nil), Context:context.Context(nil), err:""}
解决方案
Logrus的Panic()方法会将传入内容包装为logrus.Entry对象抛出,因此需要自定义断言逻辑提取并验证Message字段。
方法一:Testify Panics()结合类型断言
用Panics()捕获panic后,对panic值做类型断言,取出Message字段验证:
t.Run("verify panic message", func(t *testing.T) { // 先断言会触发panic assert.Panics(t, func() { LoadPreparedStatements() }, "LoadPreparedStatements should panic when DB prepare fails") // 捕获panic并验证Message内容 func() { defer func() { if r := recover(); r != nil { entry, ok := r.(*logrus.Entry) assert.True(t, ok, "panic value must be a *logrus.Entry") assert.Equal(t, "Loading SQL Prepared Statement Failed", entry.Message) } }() LoadPreparedStatements() }() })
方法二:自定义复用断言函数
封装专门验证Logrus Panic Message的函数,方便多处调用:
func PanicsWithLogrusMessage(t assert.TestingT, expectedMsg string, f assert.PanicTestFunc, msgAndArgs ...interface{}) bool { defer func() { if r := recover(); r != nil { entry, ok := r.(*logrus.Entry) if !ok { assert.Fail(t, "panic value is not a *logrus.Entry", msgAndArgs...) return } assert.Equal(t, expectedMsg, entry.Message, msgAndArgs...) return } assert.Fail(t, "expected panic but none occurred", msgAndArgs...) }() f() return false } // 使用示例 PanicsWithLogrusMessage(t, "Loading SQL Prepared Statement Failed", func() { LoadPreparedStatements() }, "should panic with correct log message")
补充说明
如果不需要保留Logrus上下文信息,也可以在业务代码中直接panic错误对象或字符串;但如果必须保留日志上下文,上述两种方法是更合适的选择。
内容的提问来源于stack exchange,提问作者PressingOnAlways
相关产品推荐
相关产品推荐

