如何对Go错误进行单元测试

huangapple go评论93阅读模式
英文:

How to unit test Go errors

问题

当你对具有error返回类型的函数进行单元测试时,我想知道如何正确地对这个错误进行单元测试。你是应该只检查错误是否为nil还是非nil?还是应该验证错误字符串是否与预期字符串匹配?

英文:

When you are unit testing functions that have an error return type, I was wondering how to properly unit test for this error. Are you supposed to just check if the error is nil or not nil? Or are you supposed to verify the error string matches an expected string as well?

答案1

得分: 44

在大多数情况下,你可以简单地检查错误是否为nil。

我建议只在绝对必要的情况下检查错误字符串。我通常认为错误字符串只供人类阅读。

如果你需要更多关于错误的详细信息,一个更好的选择是使用自定义错误类型。然后你可以使用err.(type)进行switch判断,看它是否是你期望的类型。
如果你需要更多详细信息,你可以让自定义错误类型包含值,然后在测试中进行检查。

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

英文:

In most cases you can just check if the error is not nil.

I'd recommend not checking error strings unless absolutely necessary. I generally consider error strings to be only for human consumption.

If you need more detail about the error, one better alternative is to have custom error types. Then you can do a switch over the err.(type) and see if it's a type you expect.
If you need even more detail, you can make the custom error types contain values which you can then check in a test.

Go's error is just an interface for a type that has an Error() string method, so implementing them yourself is straightforward.
https://blog.golang.org/error-handling-and-go

答案2

得分: 26

The testify package will come in handy.

From the docs: "EqualErrorf 断言一个函数返回了一个错误(即不是 nil),并且该错误与提供的错误相等。":

assert.EqualErrorf(t, err, expectedErrorMsg, "错误应为:%v,实际为:%v", expectedErrorMsg, err)

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

assert.Containsf(t, err.Error(), tt.wantErrMsg, "期望的错误包含 %q,实际为 %s", tt.wantErrMsg, err)

> t 的类型是 *testing.Terr 的类型是 error

英文:

The testify package will come in handy.

From the docs: "EqualErrorf asserts that a function returned an error (i.e. not nil) and that it is equal to the provided error.":

assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err)

To assert that the error message contains a substring:

assert.Containsf(t, err.Error(), tt.wantErrMsg, "expected error containing %q, got %s", tt.wantErrMsg, err)

> t is of type *testing.T and err is of type error

答案3

得分: 11

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

// ErrorContains 检查 out 中的错误消息是否包含 want 中的文本。
//
// 当 out 为 nil 时,这是安全的。如果要测试 err 是否为 nil,请使用空字符串作为 want。
func ErrorContains(out error, want string) bool {
if out == nil {
return want == ""
}
if want == "" {
return false
}
return strings.Contains(out.Error(), want)
}

示例用法:

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

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

我发现在表驱动测试中特别有用,因为我可以这样做:

tests := struct{
want string
wantErr string
}{
{
"some output",
"", // 不期望错误
},
{
"",
"out of coconuts",
}
}

它避免了与 nilerrors.New() 等打交道。

我使用 string.Contains() 而不是检查完整的错误,因为这样更健壮。我只想知道这大致是我期望的错误(而不是完全不相关的错误)。我很少检查完整的错误消息,而是使用关键词(例如 "unexpected end"、"not enough" 等)。


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

英文:

I often use this simple function to check errors:

// 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)
}

Example usage:

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

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

I find this especially useful in table-driven tests, as I can do something like:

tests := struct{
    want    string
    wantErr string
}{
    {
        "some output",
        "",  // No error expected
    },
    {
        "",
        "out of coconuts",
    }
}

It avoids mucking about with nil, errors.New(), and the like.

I use string.Contains() instead of checking the full error as that's more robust. I just want to know if this is roughly the error I'm expecting (and not a completely unrelated one). I rarely check for the full error message, but use keywords instead (e.g. "unexpected end", "not enough", etc.)


This function is part of the github.com/teamwork/test package (I am the chief author of that), but I often just copy/paste it if I use only this function and none of the others in that package.

答案4

得分: 7

是的,我测试了返回错误的函数,并检查错误消息是否匹配。但是你可以选择是要检查它还是只检查错误不是nil

假设你有一个像这样的函数:

func returnSomeErr(input int) error {
    if input > 0 {
        return nil
    }
    return errors.New("this is 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)
    }
}

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

英文:

Yes I test my function that return the error and check it if the error message match. But it is up to you whether you want to check it or just check the error is not nil.

suppose you have a function like this :

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

you can unit test the error message like this :

// 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)
   }
}

Notice that I'm using .Error() function to get the error message so that I can compare it to string. you can create another test to test if there was no error if the input data > 0.

huangapple
  • 本文由 发表于 2017年2月4日 08:23:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/42035104.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定