测试不透明的错误值

时间:2017-04-04 18:19:15

标签: unit-testing testing go

是否有最佳做法来比较Go中的非不透明错误值?

大多数代码库似乎将错误视为不透明(操作成功或失败,无法查看导致错误的内部详细信息)。

这使得编写单元测试变得容易,因为您需要做的就是根据预期的错误断言实际错误。除此之外,我见过的人最多的是比较错误字符串,以确保它至少包含一些关键信息。例如:

if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
  t.Fatalf("err: %v", err)
}

但是对于需要额外错误信息的情况(例如在需要指定无效字段名称,值,错误代码以及可能还有一些嵌套错误的表单验证中),您会怎么做?

我不能简单地执行reflect.DeepEqual(),因为错误将包含唯一的堆栈跟踪,这将使每次比较失败。此外,嵌套错误会使测试逻辑变得更加复杂,并且您需要各种容易出错的逻辑(循环,递归)来比较所需的字段。有没有一种标准的方法来测试这种性质的错误?

1 个答案:

答案 0 :(得分:1)

虽然这可能无法回答您关于检查错误的问题,而这些错误并未以正确的方式完成,但至少有一个如何以正确的方式创建和使用错误的示例。

标准库包中通常执行的操作是将错误创建为导出变量,然后可以抛出并比较这些错误。这是一个例子......但它可能是缺乏想象力的。

https://play.golang.org/p/JlpguFn2NX

package main

import (
    "errors"
    "fmt"
)

var ErrBadIdea = errors.New("that was dumb")
var ErrNoValue = errors.New("not a real value")

func DoSomething(i int) error {
    if i == 0 {
        return ErrNoValue
    }
    if i < 0 {
        return ErrBadIdea
    }
    // does something that doesn't like negative or zero values
    return nil
}

func main() {
    err := DoSomething(-1)
    fmt.Println(err == ErrBadIdea, err)
    err = DoSomething(0)
    fmt.Println(err == ErrNoValue, err)
}

这方面的一个很好的例子是标准库的database/sql包。

https://godoc.org/database/sql#pkg-variables

这些变量存在,所以你可以这样测试

if err == sql.ErrNoRows { // these are not the rows you are looking for }

它变得更好!

由于errorinterface,您所要做的就是实现它。这只需要你func Error() string。请参阅以下示例,并惊叹于interface s。

的强大功能

https://play.golang.org/p/3RFrxKGkdm

另请阅读以下有关错误的博客。

https://blog.golang.org/error-handling-and-go