Search code examples
govariablesglobal-variables

Using an error variable as package-level vs global variable


Using the Go language I am writing a function that uses a custom error variable, e.g.

func readEnv() (map[string]string, error) {
    var ErrConfig = errors.New("Configuration Error: Variables starting with the right prefix are not even")

if this {
  return nil, ErrConfig
}

I declare this as a local var to avoid declaring it as a package-level var which is not recommended (and marked as issue from the linter if I am not mistaken)

The problem arises when I want to unit test this fxn and want to also test the error path (in which case the fxn should return the above error which however has not access to.). Now, the only way I can think of to address this is to re-declare this variable in my table test.

Which is the right way? Declaring ErrConfig as a package-level variable or just re-declaring it in the unit test fxn?


Solution

  • Does it matter to the caller of readEnv() what error you return?

    If it doesn't matter, your test shouldn't care either, just check if the returned error is nil or not.

    If it matters, in your current solution callers can't do any better than you in your tests. If it matters and clients should be able to tell, you have to export some kind of mechanism to test / examine the returned error.

    One solution is to move ErrConfig to a package level variable. This is accepted, used numerous places in the standard lib too, e.g. io.EOF, io.ErrClosedPipe.

    This is not the only solution though. You could make Errconfig unexported (e.g. errConfig), and provide an exported function to test an error, e.g.:

    var errConfig = errors.New("Configuration Error: Variables starting...")
    
    func IsErrConfig(err error ) bool {
        return err == errConfig
    }
    

    This is also used in many places in the standard lib, e.g. os.IsExist(), os.IsNotExist()

    You could also make the returned error implement an exported interface, and callers can check using a type assertion if the returned error implements that, providing extra functionality for the returned error.