如何在GitHub Actions中编写预期错误的Go单元测试并通过检查?
在Go中验证预期错误并让测试通过的实现方法
要实现「验证代码返回预期错误,同时让测试通过」的需求,核心是在测试逻辑里主动判断错误是否符合预期,而非让错误直接导致测试失败。以下是具体实现方式:
1. 直接判断特定错误
针对单个错误场景,先检查是否返回错误,再验证错误是否匹配预期值:
import ( "errors" "testing" ) var ErrInvalidInput = errors.New("invalid input") func SomeFunction(input string) (string, error) { if input == "" { return "", ErrInvalidInput } return "success", nil } func TestSomeFunction_InvalidInput(t *testing.T) { _, err := SomeFunction("") // 首先确保确实返回了错误 if err == nil { t.Fatal("预期返回错误,但实际未返回任何错误") } // 验证错误是否为预期的特定错误 if !errors.Is(err, ErrInvalidInput) { t.Errorf("错误不匹配:预期%v,实际%v", ErrInvalidInput, err) } }
这种方式下,只有当「应该报错却没报」或者「报错不是预期的类型/内容」时,测试才会失败;如果错误符合预期,测试会正常通过。
2. 使用表驱动测试(多场景覆盖)
如果需要同时测试成功和失败场景,表驱动测试会更清晰,能统一管理所有测试用例:
func TestSomeFunction(t *testing.T) { testCases := []struct { name string input string expectErr bool expectedErr error }{ { name: "有效输入-正常返回", input: "valid", expectErr: false, }, { name: "无效输入-返回指定错误", input: "", expectErr: true, expectedErr: ErrInvalidInput, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result, err := SomeFunction(tc.input) if tc.expectErr { if err == nil { t.Fatalf("测试用例[%s]:预期返回错误,但实际未返回", tc.name) } if !errors.Is(err, tc.expectedErr) { t.Errorf("测试用例[%s]:错误不匹配,预期%v,实际%v", tc.name, tc.expectedErr, err) } } else { if err != nil { t.Fatalf("测试用例[%s]:预期无错误,实际返回错误%v", tc.name, err) } if result != "success" { t.Errorf("测试用例[%s]:返回结果不匹配,预期%s,实际%s", tc.name, "success", result) } } }) } }
3. 处理自定义错误类型
如果代码返回带额外字段的自定义错误类型,可以用errors.As断言错误类型,并验证字段值:
type CustomError struct { Code int Msg string } func (e *CustomError) Error() string { return e.Msg } func AnotherFunction(input int) (int, error) { if input < 0 { return 0, &CustomError{Code: 400, Msg: "input cannot be negative"} } return input * 2, nil } func TestAnotherFunction_NegativeInput(t *testing.T) { _, err := AnotherFunction(-1) if err == nil { t.Fatal("预期返回错误,但实际未返回") } // 断言错误类型为CustomError var customErr *CustomError if !errors.As(err, &customErr) { t.Errorf("错误类型不匹配:预期%T,实际%T", customErr, err) } // 验证错误字段 if customErr.Code != 400 { t.Errorf("错误码不匹配:预期%d,实际%d", 400, customErr.Code) } if customErr.Msg != "input cannot be negative" { t.Errorf("错误信息不匹配:预期%s,实际%s", "input cannot be negative", customErr.Msg) } }
关键注意事项
- 不要直接用
if err != nil { t.Fatal(err) }处理预期的错误,这会让测试直接失败,违背验证错误的初衷。 - 优先使用
errors.Is和errors.As,而非直接比较错误字符串,这能更好地处理错误包装(fmt.Errorf("wrap: %w", err))的场景。 - 所有测试用例的预期逻辑要明确:无论是成功还是失败场景,只要符合预期,测试就会通过;只有不符合预期时才触发失败。
内容的提问来源于stack exchange,提问作者delos777
相关产品推荐
相关产品推荐

