比较Go中的2个错误进行单元测试



我遇到了如下问题:在编写单元测试时比较2个错误

package main
import (
"errors"
"fmt"
"reflect"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func main() {
er1 := errors.New("database name is not exists")
er2 := errors.New("database name is not exists")

result1 := reflect.DeepEqual(er1, er2)
fmt.Println("reflect: ", result1)

result2 := cmp.Equal(er1, er2, cmpopts.EquateErrors())
fmt.Println("compare: ", result2)

result3 := errors.Is(er1, er2)
fmt.Println("errorIs: ", result3)
}

上述代码的输出为:

reflect:  true
compare:  false
errorIs:  false

我想比较2个错误,reflect.DeepEqual(er1, er2)是我应用的第一种方法,这种方法产生了我想要的输出,但这种方法有来自go lint:的警告

avoid using reflect.DeepEqual with errorsdeepequalerrors

在谷歌搜索之后,一些人告诉我一些方法是:

  • 使用cmp包进行比较:cmp.Equal(er1, er2, cmpopts.EquateErrors())
  • 使用错误包进行比较:errors.Is(er1, er2)

但以上两种方法都不能像第一种方法那样产生相同的结果(使用reflect.DeepEqual(。如何比较go lint的两个错误而不发出警告,并产生类似reflect.DeepEqual的结果Tks

根据您编写测试的方式,您可能依赖reflect.DeepEqual()并忽略linter警告
缺点是:您开始时依赖于返回的错误的内部结构。


在我们编写的测试代码中,我们使用以下模式之一:

  • 大多数时候,我们只是将误差与nil进行比较
  • 在某些情况下,我们的函数返回预定义的错误值,并测试这些特定值:
package pkg
var ErrUnboltedGizmo = errors.New("gizmo is unbolted")
// in test functions, depending on the case :
if err == pkg.ErrUnboltedGizmo { ...
// or :
if errors.Is(err, pkg.ErrUnboltedGizmo) { ...
  • 当我们的生产代码要求发现特定错误时(常见的用例是io.EOF(,我们编写的代码会尽职尽责地包装已知错误,并且我们使用errors.Is()(在生产代码和测试代码中(
  • 当仅在测试中需要松散地确认错误匹配某些内容而不是其他内容时(例如:Parse error而不是File not found(,我们只需在错误消息中搜索字符串:
if err == nil || !strings.Contains(err.Error(), "database name is not exists") {
t.Errorf("unexpected error : %s", err)
}

我发现有用的是使用cmp。与cmopts的差异。IgnoreFields忽略导致问题的特定错误字段,然后我只使用字符串对错误进行检查。包含或任何我觉得合适的东西。

所以它是这样的:

if diff := cmp.Diff(expected, got, cmpopts.IgnoreFields(expected, "ErrorField")); diff != "" { 
// found diff not including the error
}

现在只检查自己的错误,就这样。

是的,我知道你已经标记了一个解决方案,但也许它会对某人有所帮助:(

最新更新