go - 传播或解压缩结构作为测试的输入参数

标签 go struct go-testing

我想通过使用一个结构作为测试输入并使用另一个结构作为复杂测试的期望输出来缩短测试代码。
我有这样的测试代码,它可以正常工作:

func TestMyTest(*testing.T) {
    type Test struct {
        n      int
        items  map[string][]int
        order  int
        expect []string
    }
    tests := []Test{
        {
            n: 3,
            items: map[string][]int{
                "item1": []int{1, 2},
                "item2": []int{3, 4},
                "item3": []int{5, 6},
            },
            order:  1,
            expect: []string{"item1"},
        },
        // ... more test cases
    }
    for testNo, test := range tests {
        output := myTest(test.n, test.items, test.order)
        desire := test.expect
        fmt.Printf("Test %v ", testNo+1)
        if reflect.DeepEqual(output, desire) {
            fmt.Println("PASS")
        } else {
            fmt.Println("FAIL")
        }
        fmt.Println("Got:", output, "Expected:", desire)
    }
}
我的虚拟功能:
func myTest(n int, items map[string][]int, order int) []string {
    res := []string{"item1"}
    return res
}
但是,如果我有更复杂的输入和输出,我不想键入所有参数,而是将它们归为1个结构,如下所示:
func TestMyTest2(*testing.T) {
    type TestInput struct {
        n     int
        items map[string][]int
        order int
    }
    type TestExpect struct {
        expect []string
    }
    type Test struct {
        input  TestInput
        expect TestExpect
    }
    tests := []Test{
        {
            input: TestInput{
                n: 3,
                items: map[string][]int{
                    "item1": []int{10, 15},
                    "item2": []int{3, 4},
                    "item3": []int{17, 8},
                },
                order: 1,
            },
            expect: TestExpect{
                []string{"item3"},
            },
        },
        // ... more test cases
    }
    for testNo, test := range tests {
        output := myTest(test.input) // ERROR: have (TestInput) want (int, map[string][]int, int)
        desire := test.expect
        fmt.Printf("Test %v ", testNo+1)
        if reflect.DeepEqual(output, desire) {
            fmt.Println("PASS")
        } else {
            fmt.Println("FAIL")
        }
        fmt.Println("Got:", output, "Expected:", desire)
    }
}
我有错误:
have (TestInput) want (int, map[string][]int, int)
这很有意义,但我一直在努力“扩展” TestInput内部的值以传递我的函数。我想要做的就像在JS中一样,我可以将...params进行“传播”,或者在Python **params中进行“解压”。
我已经查看了herehereherehere的答案,但仍无法弄清楚。

最佳答案

使用reflect包来传播参数:

func spread(fn interface{}, args interface{}) interface{} {
    var in []reflect.Value
    s := reflect.Indirect(reflect.ValueOf(args))
    for i := 0; i < s.NumField(); i++ {
        in = append(in, s.Field(i))
    }
    out := reflect.ValueOf(fn).Call(in)
    return out[0].Interface()
}
必须导出TestInput中的字段才能正常工作。
使用方法如下:
for i, test := range tests {
    output := spread(myTest, test.input)
    desire := test.expect.expect
    if !reflect.DeepEqual(output, desire) {
        t.Errorf("%d: got %v, want %v", i, output, desire)
    }
}
Run it on the Go Playground
我认为写出参数比使用反射技巧更简单。带有参数的代码比反射代码要快,但是对于测试而言可能无关紧要。

关于go - 传播或解压缩结构作为测试的输入参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64503660/

相关文章:

go - 如何跳过失败的测试

mongodb - Go:如何对与Mongo集合兼容的代码进行单元测试?

Golang 的类型系统行为——将一个 int 除以一个隐式 float

json - XML 到 JSON 多重嵌套

go - Int* 到 Golang 中的字符串

用于填充结构字段的 C 预处理器宏

c - 使用位域运算符时的位填充

go - 进行测试可以访问生产功能,但不能访问测试功能

mongodb - 如何在mgo框架中使用mongodb 3.6的数组过滤器?

c - 将结构体数组作为指针传递给函数 (C)