Search code examples
gogo-testing

How to interrogate an error object inside a GoLang Test case?


I'm writing my first API endpoint in GoLang using GRPC/proto-buffers. I'm rather new to GoLang. Below is the API in action in the happy case:

$ grpcurl -d '{
    "field1": "A",
}' -plaintext localhost:11000 myteam.myprject.v1.MyProjectAPI/Endpoint

Response is Success:

{
    "message": "success"
}

Below is the API in action in the unhappy case:

$ grpcurl -d '{}' -plaintext localhost:11000 myteam.myprject.v1.MyProjectAPI/Endpoint

Response is Failure:

ERROR:
  Code: InvalidArgument
  Message: Required parameter 'field1' not provided

This is exactly correct behavior based on my application function shown below:

func (a *APIv1) Endpoint(ctx context.Context, msg *myprojectv1.EndpointRequest) (*myprojectv1.EndpointResponse, error) {
    if msg.Field1 == "" {
        return nil, status.Error(codes.InvalidArgument, "Required parameter 'field1' not provided")
    }
    return &myprojectv1.EndpointResponse{Message: "success"}, nil
}

I have the following two test-cases to test the happy path and unhappy path:

func TestEndpoint(t *testing.T) {
    myApiv1 := myprojecthandlersv1.New()

    t.Run("Success", func(t *testing.T) {
        res, err := myApiv1.Endpoint(context.Background(), &myprojectv1.EndpointRequest{
            Id: "A",
        })
        require.Nil(t, err)
        require.Equal(t, "success", res.Message)
    })

    t.Run("Missing argument id", func(t *testing.T) {
        _, err := myApiv1.Endpoint(context.Background(), &myprojectv1.EndpointRequest{
        })
        require.NotNil(t, err)
        require.Equal(t, codes.InvalidArgument, /* WHAT DO I PUT HERE?? */)
        require.Equal(t, "Required parameter 'field1' not provided", /* WHAT DO I PUT HERE?? */)
    })
}

But I do not know how to test the value of the error in the Test case. How can I test that the Code == InvalidArgument and Message == Required parameter 'field1' not provided?


Solution

  • You can forge the same error as you expect and then compare err you've got with it like this:

    expectedErr := status.Error(codes.InvalidArgument, "Required parameter 'field1' not provided")
    
    _, err := myApiv1.Endpoint(context.Background(), &myprojectv1.EndpointRequest{})
    require.NotNil(t, err)
    require.Equal(t, expectedErr, err)
    

    To get error message and code from err you'll probably need to use reflection on err as if I remember correctly gprc status wraps them into own private struct that is then used to concatenate into single string of format code: FOO desc: BAR and that is obtainable through err.Error().