go – golang 测试参数化

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

go - golang test parameterized

问题

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

  1. func tutu(a int) int {
  2. return a + 1
  3. }
  4. func Test_tutu(t *testing.T) {
  5. tests := []struct {
  6. input int
  7. expected int
  8. }{
  9. {input: 1, expected: 2},
  10. {input: 2, expected: 3},
  11. }
  12. for _, tt := range tests {
  13. t.Run("", func(t *testing.T) {
  14. assert.Equal(t, tutu(tt.input), tt.expected)
  15. })
  16. }
  17. }

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

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

英文:

In python I can easily do

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

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

  1. func tutu(a int) int {
  2. return a + 1
  3. }
  4. func Test_tutu(t *testing.T) {
  5. tests := []struct {
  6. input int
  7. expected int
  8. }{
  9. {input: 1, expected: 2},
  10. {input: 2, expected: 3},
  11. }
  12. for _, tt := range tests {
  13. t.Run("", func(t *testing.T) {
  14. assert.Equal(t, tutu(tt.input), tt.expected)
  15. })
  16. }
  17. }

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

  1. def parametrize(all_args_name: str, all_values: List[Any], fn: Callable):
  2. args_name = all_args_name.split(',')
  3. for values in all_values:
  4. args = {k: v for k, v in zip(args_name, values)}
  5. 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

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

  1. func parametrize[V any, T any](fn T, allValues [][]V) {
  2. v := reflect.ValueOf(fn)
  3. for _, a := range allValues {
  4. vargs := make([]reflect.Value, len(a))
  5. for i, b := range a {
  6. vargs[i] = reflect.ValueOf(b)
  7. }
  8. v.Call(vargs)
  9. }
  10. }
  11. func tutu(a int) int {
  12. return a + 1
  13. }
  14. func Test_tutu(t *testing.T) {
  15. testsArgs := [][]any{
  16. {t, 1, 2}, {t, 3, 4},
  17. }
  18. test := func(t *testing.T, input int, expected int) {
  19. assert.Equal(t, tutu(input), expected)
  20. }
  21. parametrize(test, testsArgs)
  22. }

这段代码使用了反射来实现一个参数化测试的功能。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

  1. func parametrize[V any, T any](fn T, allValues [][]V) {
  2. v := reflect.ValueOf(fn)
  3. for _, a := range allValues {
  4. vargs := make([]reflect.Value, len(a))
  5. for i, b := range a {
  6. vargs[i] = reflect.ValueOf(b)
  7. }
  8. v.Call(vargs)
  9. }
  10. }
  11. func tutu(a int) int {
  12. return a + 1
  13. }
  14. func Test_tutu(t *testing.T) {
  15. testsArgs := [][]any{
  16. {t, 1, 2}, {t, 3, 4},
  17. }
  18. test := func(t *testing.T, input int, expected int) {
  19. assert.Equal(t, tutu(input), expected)
  20. }
  21. parametrize(test, testsArgs)
  22. }

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:

确定