我必须为具有相似签名和返回值(一个对象和一个错误)的多个函数编写单元测试,这些函数必须通过相似的测试条件。 我想避免写:
func TestFunc1(t *testing.T) { // tests on return values } func TestFunc2(t *testing.T) { // tests identical for Func1 } func TestFunc3(t *testing.T) { // tests identical for Func1 } ...
(见本去操场例子更完整的上下文) (是的,去游乐场还不支持go test,只有gorun和问题6511是有没有要求该功能)
go test
gorun
为了只编写一个测试,您将 如何使用反射(reflect包):
reflect
但是我想念一个完整的示例来调用函数并在测试中使用返回的值。
一旦我理解了一切都必须使用或返回Value类型,这就是我的想法。 诀窍是使用:
ValueOf
Value.MethodByName
Value.IsNil
nil
测试代码的主要摘录:
var funcNames = []string{"Func1", "Func2", "Func3"} func TestFunc(t *testing.T) { stype := reflect.ValueOf(s) for _, fname := range funcNames { fmt.Println(fname) sfunc := stype.MethodByName(fname) // no parameter => empty slice of Value ret := sfunc.Call([]reflect.Value{}) val := ret[0].Int() // That would panic for a nil returned err // err := ret[1].Interface().(error) err := ret[1] if val < 1 { t.Error(fname + " should return positive value") } if err.IsNil() == false { t.Error(fname + " shouldn't err") } } }
在去操场上看到一个可运行的示例。
请注意,如果使用不存在的函数名称来调用该测试函数,则将出现恐慌。在这里 看到那个例子。
runtime.panic(0x126660, 0x10533140) /tmp/sandbox/go/src/pkg/runtime/panic.c:266 +0xe0 testing.func·005() /tmp/sandbox/go/src/pkg/testing/testing.go:383 +0x180 ----- stack segment boundary ----- runtime.panic(0x126660, 0x10533140) /tmp/sandbox/go/src/pkg/runtime/panic.c:248 +0x160 reflect.flag.mustBe(0x0, 0x13) /tmp/sandbox/go/src/pkg/reflect/value.go:249 +0xc0 reflect.Value.Call(0x0, 0x0, 0x0, 0xfeef9f28, 0x0, ...) /tmp/sandbox/go/src/pkg/reflect/value.go:351 +0x40 main.TestFunc(0x10546120, 0xe) /tmpfs/gosandbox-3642d986_9569fcc1_f443bbfb_73e4528d_c874f1af/prog.go:34 +0x240
去操场从那恐慌中恢复,但您的测试程序可能不会。
这就是为什么我添加到上面的测试功能:
for _, fname := range funcNames { defer func() { if x := recover(); x != nil { t.Error("TestFunc paniced for", fname, ": ", x) } }() fmt.Println(fname)
产生(参见示例)更好的输出:
Func1 Func2 Func3 Func4 --- FAIL: TestFunc (0.00 seconds) prog.go:48: Func2 should return positive value prog.go:51: Func3 shouldn't err prog.go:32: TestFunc paniced for Func4 : reflect: call of reflect.Value.Call on zero Value FAIL