Golang中如何减少多个相似测试包的重复代码

Golang中如何减少多个相似测试包的重复代码 你好,

我正在编写一个测试,该测试将遍历多个包,这些包都包含一个结构体列表(包含实际测试)和一个用于处理数据的函数。在所有包中,这个列表和函数的名称都是相同的。我希望避免在每个包中重复编写相同的X行代码,而是希望有一个单一的函数/指令组,能够遍历所有导入的测试包。

我本想搜索这个问题,但不太确定该如何搜索。

有人对如何在这种情况下减少重复有什么建议吗?

谢谢,

Rob

func main() {
    fmt.Println("hello world")
}
6 回复

您参考页面上的链接似乎不正确。不过,如果我直接访问 doi.org 并根据该ID进行搜索,确实能找到这篇论文。

谢谢。

更多关于Golang中如何减少多个相似测试包的重复代码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我简要浏览了这篇论文。事实证明,我之前已经决定采用表驱动方法。当时我并不知道这是一种通用做法,只是觉得这样很合理。看来我选择的方法得到了验证 🙂

谢谢,

Rob

rjmarshall17:

事实证明我已经决定采用表驱动方法。当时我并不知道这是一种特定的方法,只是觉得这样做很合理。看来我选择的这个方法是值得肯定的 🙂

这篇论文的深度不止于此,因为表驱动方法只是完成了一半的工作。表驱动方法本身无法解决过多的重复代码问题。

我最近发表了一篇关于大规模测试方法的文章,其中涉及到了"重复代码"这一常见问题。

希望这篇文章能有所帮助。链接如下:https://sites.google.com/view/chewkeanho/careers/researches/large-scale-unit-testing-for-go-programming-langauges

rjmarshall17:

您引用的页面链接似乎不正确。但如果我直接访问 doi.org 并搜索该ID,确实能找到这篇论文。

刚刚检查了链接。点击时可以正常访问,但不适合复制粘贴URL。显然,Google Sites将所有链接转换为其URL重定向格式。

如需直接链接,请尝试:http://doi.org/10.13140/RG.2.2.36308.76166。

在Golang中,可以使用反射(reflection)来动态遍历多个包中具有相同名称的结构体和函数,从而避免重复代码。以下是一个实现方案:

package main

import (
    "fmt"
    "reflect"
    
    "yourproject/testpkg1"
    "yourproject/testpkg2"
    "yourproject/testpkg3"
)

// 定义测试包接口
type TestPackage interface {
    GetTestCases() []TestCase
    ProcessData(data interface{}) error
}

type TestCase struct {
    Name string
    Data interface{}
}

// 统一测试运行器
func RunTests(pkg interface{}) {
    v := reflect.ValueOf(pkg)
    
    // 获取测试用例列表
    testCasesMethod := v.MethodByName("GetTestCases")
    if testCasesMethod.IsValid() {
        results := testCasesMethod.Call(nil)
        if len(results) > 0 {
            testCases := results[0].Interface().([]TestCase)
            
            // 遍历并执行每个测试用例
            for _, tc := range testCases {
                fmt.Printf("Running test: %s\n", tc.Name)
                
                // 调用处理函数
                processMethod := v.MethodByName("ProcessData")
                if processMethod.IsValid() {
                    processResults := processMethod.Call([]reflect.Value{
                        reflect.ValueOf(tc.Data),
                    })
                    if len(processResults) > 0 {
                        if err, ok := processResults[0].Interface().(error); ok && err != nil {
                            fmt.Printf("Test %s failed: %v\n", tc.Name, err)
                        }
                    }
                }
            }
        }
    }
}

func main() {
    // 导入的测试包实例
    packages := []interface{}{
        testpkg1.TestPackage{},
        testpkg2.TestPackage{},
        testpkg3.TestPackage{},
    }
    
    // 遍历所有包执行测试
    for _, pkg := range packages {
        fmt.Printf("Testing package: %T\n", pkg)
        RunTests(pkg)
    }
}

假设你的测试包结构如下:

// testpkg1/testpkg1.go
package testpkg1

type TestPackage struct{}

func (tp TestPackage) GetTestCases() []TestCase {
    return []TestCase{
        {Name: "Test1", Data: "data1"},
        {Name: "Test2", Data: 123},
    }
}

func (tp TestPackage) ProcessData(data interface{}) error {
    fmt.Printf("Processing data: %v\n", data)
    return nil
}
// testpkg2/testpkg2.go  
package testpkg2

type TestPackage struct{}

func (tp TestPackage) GetTestCases() []TestCase {
    return []TestCase{
        {Name: "TestA", Data: []string{"a", "b"}},
        {Name: "TestB", Data: map[string]int{"x": 1}},
    }
}

func (tp TestPackage) ProcessData(data interface{}) error {
    fmt.Printf("Processing complex data: %v\n", data)
    return nil
}

这个方案通过反射动态调用每个包中相同名称的方法,实现了代码复用。所有测试包只需要遵循相同的接口约定(包含GetTestCasesProcessData方法),主测试运行器就能统一处理。

回到顶部