go – golang 测试参数化

huangapple go评论65阅读模式
英文:

go - golang test parameterized

问题

在Go语言中,你可以使用测试表格(test table)的方式来实现类似的功能,而无需自己编写循环。下面是相应的Go代码:

func tutu(a int) int {
	return a + 1
}

func Test_tutu(t *testing.T) {
	tests := []struct {
		input    int
		expected int
	}{
		{input: 1, expected: 2},
		{input: 2, expected: 3},
	}

	for _, tt := range tests {
		t.Run("", func(t *testing.T) {
			assert.Equal(t, tutu(tt.input), tt.expected)
		})
	}
}

这段代码使用了一个结构体切片来定义测试用例,每个测试用例包含一个输入值和一个期望的输出值。然后,通过遍历测试用例切片,在每次循环中使用t.Run函数来执行单个测试,并使用断言函数assert.Equal来验证结果。

希望对你有所帮助!如果还有其他问题,请随时提问。

英文:

In python I can easily do

@pytest.mark.parametrize('input, expected', [(1, 2), [2, 3]])
def test_tutu(input, expected):
    assert input + 1 == expected

How can I do the same in golang ? without writting myself a loop

func tutu(a int) int {
	return a + 1
}

func Test_tutu(t *testing.T) {
	tests := []struct {
		input    int
		expected int
	}{
		{input: 1, expected: 2},
		{input: 2, expected: 3},
	}

	for _, tt := range tests {
		t.Run("", func(t *testing.T) {
			assert.Equal(t, tutu(tt.input), tt.expected)
		})
	}
}

So what would be the equivalent of this python parametrize in golang ?

def parametrize(all_args_name: str, all_values: List[Any], fn: Callable):
    args_name = all_args_name.split(',')
    for values in all_values:
        args = {k: v for k, v in zip(args_name, values)}
        fn(**args)

答案1

得分: 0

最接近GO的功能是subtests,但你仍然需要编写for循环,就像你在第二个示例中已经做的那样。

英文:

The closest thing GO has is subtests, but you would still need to write the for loop, like you already did in the second example.

答案2

得分: 0

我找到了一种使用反射的方法。

func parametrize[V any, T any](fn T, allValues [][]V) {
	v := reflect.ValueOf(fn)
	for _, a := range allValues {
		vargs := make([]reflect.Value, len(a))

		for i, b := range a {
			vargs[i] = reflect.ValueOf(b)
		}
		v.Call(vargs)
	}
}

func tutu(a int) int {
	return a + 1
}

func Test_tutu(t *testing.T) {
	testsArgs := [][]any{
		{t, 1, 2}, {t, 3, 4},
	}
	test := func(t *testing.T, input int, expected int) {
		assert.Equal(t, tutu(input), expected)
	}
	parametrize(test, testsArgs)
}

这段代码使用了反射来实现一个参数化测试的功能。parametrize 函数接受一个函数 fn 和一个二维切片 allValues,其中 fn 是一个泛型函数,allValues 是一个包含多组参数的切片。在函数内部,通过反射获取 fn 的值,并遍历 allValues 中的每一组参数。然后,使用反射将参数转换为 reflect.Value 类型,并调用 v.Call(vargs) 来执行函数。

在示例代码中,tutu 函数是一个简单的示例函数,它接受一个整数参数并返回参数加一的结果。Test_tutu 函数是一个测试函数,它使用 parametrize 函数来对 tutu 函数进行参数化测试。testsArgs 是一个包含多组测试参数的切片,每一组参数都是一个切片,第一个元素是 t(测试对象),后面的元素是输入参数。test 函数是一个测试辅助函数,它接受 t、输入参数和期望结果,并使用 assert.Equal 来进行断言判断。

通过使用 parametrize 函数,可以方便地对函数进行参数化测试,减少了重复编写测试代码的工作量。

英文:

I found a way using reflect

func parametrize[V any, T any](fn T, allValues [][]V) {
	v := reflect.ValueOf(fn)
	for _, a := range allValues {
		vargs := make([]reflect.Value, len(a))

		for i, b := range a {
			vargs[i] = reflect.ValueOf(b)
		}
		v.Call(vargs)
	}
}

func tutu(a int) int {
	return a + 1
}

func Test_tutu(t *testing.T) {
	testsArgs := [][]any{
		{t, 1, 2}, {t, 3, 4},
	}
	test := func(t *testing.T, input int, expected int) {
		assert.Equal(t, tutu(input), expected)
	}
	parametrize(test, testsArgs)
}

huangapple
  • 本文由 发表于 2022年7月4日 20:13:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/72856565.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定