I am trying out error wrapping in go and have a function that returns a wrapped custom error type. What I want to do is iterate over a list of expected errors and test whether the function's output contains these expected errors.
I found that putting the custom error into []error
means that the type of the custom error will be *fmt.wraperror
, which means errors.as( )
almost always returns true.
As an example, consider the following code:
package main import ( "errors" "fmt" ) type anothererror struct { } func (e *anothererror) error() string { return "another error" } type missingattrerror struct { missingattr string } func (e *missingattrerror) error() string { return fmt.sprintf("missing attribute: %s", e.missingattr) } func dosomething() error { e := &missingattrerror{missingattr: "key"} return fmt.errorf("dosomething(): %w", e) } func main() { err := dosomething() expectederrone := &missingattrerror{} expectederrtwo := &anothererror{} expectederrs := []error{expectederrone, expectederrtwo} fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrone, errors.as(err, &expectederrone)) fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrtwo, errors.as(err, &expectederrtwo)) for i := range expectederrs { fmt.printf("is err '%v' type '%t'?: %t\n", err, expectederrs[i], errors.as(err, &expectederrs[i])) } }
The output is
is err 'dosomething(): missing attribute: key' type '*main.missingattrerror'?: true is err 'dosomething(): missing attribute: key' type '*main.anothererror'?: false is err 'dosomething(): missing attribute: key' type '*fmt.wraperror'?: true is err 'dosomething(): missing attribute: key' type '*fmt.wraperror'?: true
Ideally I would like the output to be
Is err 'DoSomething(): missing attribute: Key' type '*main.MissingAttrError'?: true Is err 'DoSomething(): missing attribute: Key' type '*main.AnotherError'?: false Is err 'DoSomething(): missing attribute: Key' type '*main.MissingAttrError'?: true Is err 'DoSomething(): missing attribute: Key' type '*main.AnotherError'?: false
The reason for the error is that I want to be able to define a list of expected errors for each test case entry. Suppose I know that providing certain inputs to a function will cause it to follow a path and return errors containing a specific error.
How do I convert the *fmt.wraperror
type from the []error
slice back to the original type so that I can use it with error.as
?
I know I can use to cast it to a specific type. (anothererror)
, but in order to make it work when iterating over slices, I have to do this for every possible error the function might return, no? )
You can cheat using the following method errors.as
:
func main() { err := DoSomething() m := &MissingAttrError{} a := &AnotherError{} expected := []any{&m, &a} for i := range expected { fmt.Printf("Is err '%v' type '%T'?: %t\n", err, expected[i], errors.As(err, expected[i])) } }
The type printed is not what you expect, but errors.as
works as it should.
The reason your example doesn't work is that what you're passing to errors.as
is *error
. Therefore, the wrapped error value (i.e. err
) is assigned directly to the target value. In my example, the value passed to errors.as
is **anothererror
, and err
is not assignable to *anothererror
.
The above is the detailed content of Concrete type error snippet in Golang. For more information, please follow other related articles on the PHP Chinese website!