【问题标题】:How to test a collection of functions by reflection in Go?如何在 Go 中通过反射测试一组函数?
【发布时间】:2014-01-16 09:52:51
【问题描述】:

我必须为具有相似签名和返回值(一个对象和一个错误)的几个函数编写单元测试,这些函数必须通过相似的测试条件。
我想避免写作:

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

(有关更完整的上下文,请参阅 this go playground example
(是的,go Playground 还不支持 go test,只有 go runissue 6511 可以请求该功能)

您将如何使用反射 (reflect package) 以便只编写一个测试:

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

我见过:

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

【问题讨论】:

    标签: function unit-testing reflection go


    【解决方案1】:

    一旦我明白一切都必须使用或返回type Value,这就是我想出的。
    诀窍是使用:

    测试代码的主要摘录:

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

    查看runnable example in go playground


    请注意,如果您使用不存在的函数名调用该测试函数,则会出现恐慌。
    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 从恐慌中恢复,但您的测试程序可能不会。

    这就是我在上面添加测试功能的原因:

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

    这会产生 (see example) 更好的输出:

    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
    

    【讨论】:

      猜你喜欢
      • 2016-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-04
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      • 2023-04-02
      相关资源
      最近更新 更多