英文:
Error type checking in Go for unit table tests
问题
我想要测试返回的错误类型与预期结果的测试表的类型,像这样:
var tabletest = []struct{
instruction string
want string
err error
}{
{"synonym for hi", "hello", nil}, // 输入,返回值,错误类型
{"synonym for hig", "", TranslationError{}},
{"sssnymm for hi", "", InstructionError{}},
}
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// 检查错误类型
// 检查结果类型
}
}
在上面的示例中,根据发生的错误类型返回不同的错误子类。你可以想象,虚构的 Thesaurus 函数的调用者会根据每种错误类型进行不同的处理。
如何以惯用方式断言返回的错误类型和预期的错误类型相同?
英文:
I want to test the type of the error returned against a table test of expected results, like so:
var tabletest = []struct{
instruction string
want string
err error
}{
{"synonym for hi", "hello", nil}, // input, retval, errtype
{"synonym for hig", "", TranslationError{}},
{"sssnymm for hi", "", InstructionError{}},
}
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// check error type
// check result type
}
}
In the example above, different error sub-classes are returned based on the type of error that occurred. You may imagine that the caller of the made-up Thesaurus function would handle each error type differently.
What is the idiomatic way to assert that the type of error returned, and the type of error expected, are the same?
答案1
得分: 5
使用type
开关。
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// 不使用&&,因为我们想捕获所有err为nil的情况
if err == nil {
if testcase.err != nil {
// 失败
}
continue
}
switch err.(type) {
case TranslationError:
if _,ok := (testcase.err).(TranslationError); !ok {
// 失败
}
case InstructionError:
if _,ok := (testcase.err).(InstructionError); !ok {
// 失败
}
default:
// 无法识别的错误,失败
}
}
}
这绝对不如使用reflect
的方式简洁,但我认为它更符合Go语言的风格,更加明确。
英文:
Use a type
switch.
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// Don't use && because we want to trap all cases where err is nil
if err == nil {
if testcase.err != nil {
// failure
}
continue
}
switch err.(type) {
case TranslationError:
if _,ok := (testcase.err).(TranslationError); !ok {
// failure
}
case InstructionError:
if _,ok := (testcase.err).(InstructionError); !ok {
// failure
}
default:
// Unrecognized error, failure
}
}
It's definitely not as succinct as the reflect
way of doing it, but I think it's more Go-ish and explicit.
答案2
得分: 4
这里还有一个成语:
在同义词库中...
import "errors"
var (
TranslationError = errors.New("")
InstructionError = errors.New("")
)
在测试用例中...
if err != testcase.err {
}
然而,我认为在这个成语中,错误必须事先定义好(即消息不能更改)。
英文:
There's also this idiom:
In Thesaurus...
import "errors"
var (
TranslationError = errors.New("")
InstructionError = errors.New("")
)
In Testcase...
if err != testcase.err {
}
However, I think in this idiom the errors must be defined in advance (i.e. the message cannot be changed).
答案3
得分: 2
reflect.TypeOf可以完成这个任务:
import "reflect"
...
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// 检查错误类型
if goterr, wanterr := reflect.TypeOf(err), reflect.TypeOf(testcase.err);
goterr != wanterr {
t.Errorf("对于指令 %q,出现了意外的错误:%q。期望的是 %q",
testcase.instruction, goterr, wanterr)
}
// 检查结果类型
if want := testcase.want; got != want {
t.Errorf("对于指令 %q,得到了 %q,期望的是 %q",
testcase.instruction, got, want)
}
}
}
是否符合惯用用法由社区决定。
英文:
reflect.TypeOf does the job:
import "reflect"
...
func TestThesaurus(t *Testing) {
for _, testcase := range tabletest {
got, err := Thesaurus(testcase.instruction)
// check error type
if goterr, wanterr := reflect.TypeOf(err), reflect.TypeOf(testcase.err);
goterr != wanterr {
t.Errorf("For instruction %q, unexpected error: %q. Wanted %q",
testcase.instruction, goterr, wanterr)
}
// check result type
if want := testcase.want; got != want {
t.Errorf("For instruction %q, got %q, want %q.",
testcase.instruction, got, want)
}
}
}
Whether or not it's idiomatic is for the community to decide.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论