传播或解压结构作为测试的输入参数
Spread or unpack struct as input parameter for test
我想通过使用一个结构进行测试输入和另一个结构进行复杂测试的测试所需输出来缩短我的测试代码。
我有这样的测试代码并且它有效:
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
中“解压”。
我查看了答案, here, here and ,但还是没弄明白。
使用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)
}
}
我认为写出参数比使用反射技巧更简单。写出参数的代码比反射代码更快,但这对测试来说可能无关紧要。
我想通过使用一个结构进行测试输入和另一个结构进行复杂测试的测试所需输出来缩短我的测试代码。
我有这样的测试代码并且它有效:
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
中“解压”。
我查看了答案
使用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)
}
}
我认为写出参数比使用反射技巧更简单。写出参数的代码比反射代码更快,但这对测试来说可能无关紧要。