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

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?

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

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.

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.