面试题答案
一键面试1. panic 与 recover 对测试流程和结果的影响
- 单元测试:
- 在Go语言单元测试中,当测试函数内部发生
panic
时,如果没有recover
,测试会立即终止,并标记为失败。例如:
- 在Go语言单元测试中,当测试函数内部发生
package main
import "testing"
func TestPanic(t *testing.T) {
panic("test panic")
}
这个测试会以失败告终,输出类似panic: test panic
的错误信息。
- 若使用
recover
,可以捕获panic
并继续执行后续代码。比如:
package main
import "testing"
func TestRecover(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("recovered from panic: %v", r)
}
}()
panic("test panic")
}
在这个例子中,recover
捕获了panic
,并通过t.Errorf
输出错误信息,测试依然会标记为失败,但程序不会直接终止测试,而是可以继续执行defer
函数中的清理逻辑。
- 集成测试:
- 与单元测试类似,未处理的
panic
会导致集成测试立即失败。在集成测试中,多个组件相互交互,如果某个组件在测试中panic
,整个集成测试就会中断。 - 若使用
recover
,可以在捕获panic
后,根据具体情况处理,比如记录错误日志,清理测试环境等,但测试结果依然会被标记为失败,除非recover
后能修复问题并让测试继续按预期执行。
- 与单元测试类似,未处理的
2. 在复杂测试逻辑中合理运用
- 确保测试的准确性:
- 明确 panic 预期:在测试逻辑中,有时会故意引发
panic
来测试错误处理逻辑。使用recover
时,要确保能准确判断panic
的原因是否符合预期。例如:
- 明确 panic 预期:在测试逻辑中,有时会故意引发
package main
import "testing"
func someFunction() {
panic("specific error")
}
func TestExpectedPanic(t *testing.T) {
defer func() {
if r := recover(); r != "specific error" {
t.Errorf("unexpected panic: %v", r)
}
}()
someFunction()
}
这样可以准确验证panic
是否是我们期望的错误类型,保证测试的准确性。
- 保证测试的稳定性:
- 清理资源:在复杂测试逻辑中,可能会涉及到打开文件、连接数据库等操作。使用
recover
捕获panic
后,要确保在defer
函数中清理这些资源,防止资源泄漏。例如:
- 清理资源:在复杂测试逻辑中,可能会涉及到打开文件、连接数据库等操作。使用
package main
import (
"database/sql"
"fmt"
"testing"
_ "github.com/lib/pq"
)
func TestDatabase(t *testing.T) {
db, err := sql.Open("postgres", "user=test dbname=test sslmode=disable")
if err != nil {
t.Fatalf("failed to open database: %v", err)
}
defer func() {
if r := recover(); r != nil {
t.Errorf("recovered from panic: %v", r)
}
db.Close()
}()
// 假设这里的数据库操作可能会 panic
_, err = db.Exec("invalid SQL")
if err != nil {
t.Errorf("database operation error: %v", err)
}
}
在这个例子中,无论是否发生panic
,都会在defer
函数中关闭数据库连接,保证测试的稳定性。
- 避免掩盖真实问题:虽然
recover
可以捕获panic
,但要避免过度使用,导致真正的错误被掩盖。应根据具体情况,确保错误能被适当报告和处理,以利于定位和修复问题。