英文:
Using errors.As() while iterating over test struct returning second argument to errors.As should not be *error
问题
我目前正在为一个包编写一些单元测试,其中一个函数可以返回多种类型的错误。我已经定义了这个结构:
tests := []struct {
name string
data string
url string
status int
}
我想使用errors.As()
在我测试的错误中查找test.err
。我在我的测试中使用的一个示例结构如下:
{
name: "url not available",
err: &url.Error{},
data: srvData,
url: "a",
status: http.StatusOK,
}
我想要对实现了错误接口的不同结构类型使用errors.As
。因此,正如你在结构中看到的那样,我将err定义为error类型。正如你所看到的,我使用了&url.Error{}
,它应该实现了错误接口。
t.Run(test.name, func(t *testing.T) {
data, err := i.getID(url)
if err != nil {
require.NotNil(t, test.err)
assert.True(t, errors.As(err, &test.err))
} else {
// ...
}
})
然而,上述使用errors.As
会返回以下错误信息:
errors.As
的第二个参数不应该是*error类型
根据我的理解,errors.As()
接受any
作为第二个参数,所以我对不能使用*error
感到困惑。
我还尝试将测试结构中的err
字段更改为interface{}
,但这样做会导致所有断言都通过,无论目标是否存在于错误中。
我找不到如何以类似上述方式使用errors.As()
来处理实现了错误接口的不同类型的解决方案,所以目前我依赖于使用Contains()
。想知道是否有人能提供一些见解。
英文:
I'm currently writing some unit tests for a package in which a function can return several types of errors. I've defined the struct as:
tests := []struct {
name string
data string
url string
status int
}
And would like to use errors.As()
to find test.err
within the error I test upon. An example struct that I used within my tests is for example:
{
name: "url not available",
err: &url.Error{},
data: srvData,
url: "a",
status: http.StatusOK,
},
I want to use errors.As
for different struct types that implement the error interface. Hence as you can see within the struct I have defined err as error. As can be seen I use &url.Error{}
which should be implementing the error interface.
t.Run(test.name, func(t *testing.T) {
data, err := i.getID(url)
if err != nil {
require.NotNil(t, test.err)
assert.True(t, errors.As(err, &test.err))
} else {
// ...
}
})
However, using errors.As
as above returns
> second argument to errors.As
should not be *error
Now to my understanding errors.As() accepts any
as second argument, so I'm confused as to why I can't use *error.
I have also tried changing the err
field within the test struct to interface{} instead; however doing so made all assertion pass, regardless of whether the target was present within the error.
I couldn't find a solution on how to use errors.As()
for different types that implement the error interface in a similar fashion as above, so for now I rely on using Contains()
instead. Was wondering if anyone could provide some insight.
答案1
得分: 0
指向错误类型的指针不满足error
接口,这就是为什么As
函数的第二个参数是any
类型的原因。为了直接将您想要的类型存储在.err
字段中,该字段也必须是any
类型。
然而,因为您将这个指针值包装在一个接口中,您需要使用类型断言或反射来将该值取回以进行检查:
var testErr any = new(*url.Error)
_, err := http.Get("http://error.error/")
if errors.As(err, testErr) {
fmt.Println(reflect.ValueOf(testErr).Elem())
}
英文:
A pointer to an error type does not satisfy the error
interface, which is why the second argument to As
is of type any
. In order to store the type you want directly in your .err
field, that field will also have to be of type any
.
However because you have wrapped this pointer value in an interface, you will need to use a type assertion or reflection to get that value back out for inspection:
var testErr any = new(*url.Error)
_, err := http.Get("http://error.error/")
if errors.As(err, testErr) {
fmt.Println(reflect.ValueOf(testErr).Elem())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论