How to unit test Go errors

46,388

Solution 1

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

Solution 2

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

Solution 3

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.

Solution 4

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.

Share:
46,388
GabeMeister
Author by

GabeMeister

Graduated with BS in Computer Science from WSU. Associate software engineer at SEL.

Updated on July 09, 2022

Comments

  • GabeMeister
    GabeMeister almost 2 years

    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?

  • GabeMeister
    GabeMeister over 7 years
    I do like the idea of using custom error types, that would definitely simplify things.
  • Michael Mallett
    Michael Mallett almost 2 years
    I know this is a bit old, but I don't think this should be the accepted answer. Comparing the error strings is important in tests for me as they are values like anything else. When writing a unit test check not only that the error returned is what you expect, but also that the correct error wrapping has been applied. Custom error types create a strong coupling with the caller, which is often not what you want. dave.cheney.net/2016/04/27/…