如何单元测试Go错误

Gab*_*ter 13 error-handling unit-testing go

当你是具有error返回类型的单元测试函数时,我想知道如何正确地测试此错误.您是否应该检查错误是否为零?或者您是否应该验证错误字符串是否与预期的字符串匹配?

Guj*_*ana 8

是的我测试我的函数返回错误并检查错误消息是否匹配.但是,您是否要检查它或仅检查错误是由您自己决定的nil.

假设你有这样的功能:

func returnSomeErr(input int)error{
    if input > 0{
        return nil
    }
    return errors.New("this is error message")
}
Run Code Online (Sandbox Code Playgroud)

您可以像这样单元测试错误消息:

// testing tot get error message
func TestReturnSomeErr(t *testing.T){
   Expected := "this is error message"
   actual := returnSomeErr(-1)

   if actual.Error() != Expected{
        t.Errorf("Error actual = %v, and Expected = %v.", actual, test.Expected)
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我正在使用.Error()函数来获取错误消息,以便我可以将其与字符串进行比较.您可以创建另一个测试来测试输入数据是否没有错误> 0.


Mar*_*oij 7

我经常使用这个简单的函数来检查错误:

// ErrorContains checks if the error message in out contains the text in
// want.
//
// This is safe when out is nil. Use an empty string for want if you want to
// test that err is nil.
func ErrorContains(out error, want string) bool {
    if out == nil {
        return want == ""
    }
    if want == "" {
        return false
    }
    return strings.Contains(out.Error(), want)
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

if !ErrorContains(err, "unexpected banana") {
    t.Errorf("unexpected error: %v", err)
}

if !ErrorContains(err, "") {
    t.Errorf("unexpected error: %v", err)
}
Run Code Online (Sandbox Code Playgroud)

我发现这在表驱动测试中特别有用,因为我可以执行以下操作:

tests := struct{
    want    string
    wantErr string
}{
    {
        "some output",
        "",  // No error expected
    },
    {
        "",
        "out of coconuts",
    }
}
Run Code Online (Sandbox Code Playgroud)

它避免摆弄nilerrors.New()等等。

我使用string.Contains()而不是检查完整错误,因为它更健壮。我只是想知道这是否是我期望的错误(而不是完全不相关的错误)。我很少检查完整的错误消息,而是使用关键字(例如“意外结束”、“不够”等)


这个函数是github.com/teamwork/test包的一部分(我是它的主要作者),但如果我只使用这个函数而不使用该包中的其他函数,我通常只是复制/粘贴它。


小智 6

testify会派上用场。

来自文档:“EqualErrorf 断言函数返回错误(即 not nil)并且它等于提供的错误。”:

assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err)
Run Code Online (Sandbox Code Playgroud)

要断言错误消息包含子字符串:

assert.Containsf(t, err.Error(), tt.wantErrMsg, "expected error containing %q, got %s", tt.wantErrMsg, err)
Run Code Online (Sandbox Code Playgroud)

t 是类型*testing.T并且err是类型error


小智 5

在大多数情况下,您可以检查错误是否不是nil。

我建议除非绝对必要,否则不要检查错误字符串。我通常认为错误字符串仅供人类使用。

如果您需要有关错误的更多详细信息,一种更好的选择是使用自定义错误类型。然后,您可以切换err。(类型),并查看它是否为您期望的类型。如果需要更多详细信息,可以使自定义错误类型包含值,然后可以在测试中进行检查。

Go的错误只是具有Error() string方法的类型的接口,因此,自己实现就很简单。 https://blog.golang.org/error-handling-and-go

  • 我知道这有点旧,但我认为这不应该是公认的答案。对我来说,比较错误字符串在测试中很重要,因为它们是像其他任何东西一样的值。编写单元测试时,不仅要检查返回的错误是否符合您的预期,还要检查是否已应用正确的错误包装。自定义错误类型与调用者建立了强耦合,这通常不是您想要的。https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-graceously (8认同)