3

我遇到了如下问题: 编写单元测试时比较 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包进行比较:errors.Is(er1, er2)

但是上述两种方法都不能产生与第一种方法相同的结果(使用 reflect.DeepEqual)。我如何在没有警告的情况下比较 2 个错误go lint并产生像reflect.DeepEqual Tks这样的结果

4

1 回答 1

3

根据您编写测试的方式,您可能会依赖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和 not File not found),我们只需在错误消息中搜索字符串:
if err == nil || !strings.Contains(err.Error(), "database name is not exists") {
    t.Errorf("unexpected error : %s", err)
}
于 2021-04-28T10:18:05.860 回答