Using errors.As() while iterating over test struct returning second argument to errors.As should not be *error

huangapple go评论84阅读模式
英文:

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())
}

huangapple
  • 本文由 发表于 2023年4月26日 20:30:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76110748.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定