测试Go错误处理需验证函数在异常输入下是否返回预期错误,并检查调用方正确响应;2. 使用errors.New创建的预定义错误可通过==比较,适用于包级变量;3. Go 1.13后推荐用fmt.Errorf搭配%w包装错误,利用errors.Is判断是否等于目标错误(支持链式匹配),errors.As判断错误链中是否存在指定类型;4. 对于外部依赖如数据库或网络调用,应通过接口抽象并注入返回错误的mock实现来触发错误路径;5. 综合构造错误输入、使用errors.Is/As及mock技术可有效覆盖多数实际场景中的错误处理逻辑测试。

在Go语言中测试错误处理逻辑是确保程序健壮性的关键部分。重点在于验证函数在异常输入或失败场景下是否返回预期的错误,并且调用方能正确响应这些错误。
使用标准库中的 errors 包进行错误比对
Go中很多函数通过返回 error 类型来表示失败。测试时,你可以检查返回的 error 是否与预期一致。
对于预定义错误(如使用 errors.New 创建),可以直接比较:
- 使用 == 比较错误值是否相等
- 注意:仅适用于包级变量错误,不适用于动态生成的错误
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 测试除零错误
func TestDivideByZero(t *testing.T) {
_, err := divide(1, 0)
if err == nil {
t.Fatal("expected error, got nil")
}
if err.Error() != "division by zero" {
t.Errorf("expected 'division by zero', got '%s'", err.Error())
}
}
使用 errors.Is 和 errors.As 进行更灵活的错误判断
从 Go 1.13 开始,推荐使用 fmt.Errorf 配合 %w 包装错误,并利用 errors.Is 或 errors.As 进行断言。
立即学习“go语言免费学习笔记(深入)”;
- errors.Is(err, target) 判断 err 是否等于目标错误(支持包装链)
- errors.As(err, &target) 判断 err 链中是否存在指定类型的错误
var ErrNotFound = errors.New("not found")
func getData(id string) (string, error) {
if id == "" {
return "", fmt.Errorf("invalid id: %w", ErrNotFound)
}
// ...
}
func TestGetData_ErrorWrapped(t *testing.T) {
_, err := getData("")
if !errors.Is(err, ErrNotFound) {
t.Errorf("expected error to wrap ErrNotFound")
}
}
模拟外部依赖以触发错误路径
真实项目中错误常来自数据库、网络请求等。可通过接口抽象并注入模拟实现来触发错误。
- 定义数据访问接口
- 编写一个总是返回错误的 mock 实现
- 在测试中传入该 mock
FetchUser(id string) (*User, error)
}
type MockDB struct {
Err error
}
func (m *MockDB) FetchUser(id string) (*User, error) {
return nil, m.Err
}
func TestUserService_GetUser_Error(t *testing.T) {
mockDB := &MockDB{Err: errors.New("db failed")}
svc := UserService{DB: mockDB}
_, err := svc.GetUser("123")
if err == nil {
t.Fatal("expected error from DB")
}
} 基本上就这些。关键是构造能产生错误的输入或环境,然后检查返回的 error 是否符合预期。结合 errors.Is/As 和 mock 技术,可以覆盖大多数实际场景。










