在 Go 中是否有比较非不透明错误值的最佳实践?
大多数代码库似乎将错误视为不透明的(操作成功或失败,无法看到有关导致错误的内部细节)。
这使得编写单元测试变得容易,因为您需要做的就是根据预期错误断言实际错误。除此之外,我见过人们做的最多的事情就是比较错误字符串以确保它至少包含一些关键信息。例如:
if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
t.Fatalf("err: %v", err)
}
但是对于需要额外错误信息的情况(比如在表单验证中,您需要指定无效的字段名称、值、错误代码以及可能的一些嵌套错误),您会怎么做?
我不能简单地执行 reflect.DeepEqual()
,因为错误将包含一个唯一的堆栈跟踪,这将使比较每次都失败。此外,嵌套错误会使测试逻辑更加复杂,您将需要各种容易出错的逻辑(循环、递归)来比较所需的字段。是否有测试这种性质的错误的标准方法?
最佳答案
虽然这可能无法回答您有关检查未正确完成的错误的问题,但这里至少是一个示例,说明如何以正确的方式创建和使用错误。
标准库包中通常做的是将错误创建为导出变量,然后可以抛出这些错误并进行比较。这是一个示例……无论它多么缺乏想象力。
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 }
越来越好!
因为error
是一个接口(interface)
,所以您所要做的就是实现它。这只需要您有一个 func Error() string
。请参阅以下示例并惊叹于 interface
的强大功能。
https://play.golang.org/p/3RFrxKGkdm
另请阅读以下有关错误的博客。
关于unit-testing - 测试非不透明错误值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43214776/