如何在Go中通过反射来测试一系列函数? [英] How to test a collection of functions by reflection in Go?

查看:95
本文介绍了如何在Go中通过反射来测试一系列函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须为几个具有相似签名和返回值(一个对象和一个错误)的函数编写单元测试,它们必须通过类似的测试条件。

我想避免编写:

func TestFunc1(t * testing.T){
//测试返回值
$ b $ func TestFunc2(t * testing.T){
//测试相同的Func1
}
func TestFunc3(t * testing.T){
//测试结果与Func1相同


code $ $ $ $ $ $ $ $ $ $ $ $ $(参见<一个href =http://play.golang.org/p/enAdaVo0HS =nofollow noreferrer>这个go playground例子更完整的上下文)

(yes,go游乐场还不支持 go test ,只有 go run issue 6511 是否有申请该功能的要求)



你会如何使用反射( reflect package ),以便只写一个测试:




  • 依次调用每个函数?
  • 测试它们的返回值吗?



我见过:



但是我错过了一个调用函数和在测试中使用返回值的完整示例。

解决方案

一旦我了解到所有内容都必须使用或返回键入值,此处我我想到了什么。

诀窍是使用:



测试代码的主要提取:



  var funcNames = [] string {Func1,Func2,Func3} 

func TestFunc .t){
stype:= reflect.ValueOf(s)
for _,fname:= range funcNames {

fmt.Println(fname)

sfunc:= stype.MethodByName(fname)
//无参数=>空价值
ret:= sfunc.Call([] reflect.Value {})

val:= ret [0] .Int()

/ /那会恐慌为零返回err
// err:= ret [1] .Interface()。(error)
err:= ret [1]

如果val< 1 {
t.Error(fname +应该返回正值)
}
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
-----堆栈段边界-----
运行时.panic(0x126660,0x10533140)
/tmp/sandbox/go/src/pkg/runtime/panic.c:248 + 0x160
reflect.flag.must Be(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 {

推迟func(){
如果x:= recover(); x!= nil {
t.Error(TestFunc paniced for,fname,:,x)
}
}()
fmt.Println(fname)

产生(

  Func1 
Func2
Func3
Func4
--- FAIL:TestFunc(0.00秒)
prog.go:48:Func2应该返回正值
prog。去:51:Func3不应该错误
prog.go:32:TestFunc为Func4 paniced:反映:调用reflect.Value.Call零价值
失败


I have to write unit tests for several functions with similar signature and return values (an object and an error), which must pass similar test conditions.
I would like to avoid writing:

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
}
...

(See this go playground example for a more complete context)
(yes, go playground doesn't support yet go test, only go run, and issue 6511 is there to request that feature)

How would you use reflection (reflect package) in order to write only one test which would:

  • call each function in turn?
  • test their return value?

I have seen:

But I miss a complete example for calling functions and using the returned values in a test.

解决方案

Once I understood that everything must use or return the type Value, here is what I came up with.
The trick is to use:

Main extract of the test code:

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")
        }

    }
}

See a runnable example in go playground.


Note that if you are calling that test function with a non-existent function name, that will panic.
See that example here.

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

Go playground recover from that panic, but your test program might not.

That is why I added to the test function above:

for _, fname := range funcNames {

    defer func() {
        if x := recover(); x != nil {
            t.Error("TestFunc paniced for", fname, ": ", x)
        }
    }()
    fmt.Println(fname)

That produces (see example) a much nicer output:

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

这篇关于如何在Go中通过反射来测试一系列函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆